AI-Assisted Development

Becoming a Vibe Engineer

In this article
  1. The Engineer's Field Guide to AI-Assisted Development
  2. Table of Contents
  3. The 6 Levels of AI Autonomy
  4. Installation
  5. Claude Code Commands
  6. Keyboard Shortcuts
  7. Sessions, Checkpoints & Git
  8. CLAUDE.md — The Project Brain
  9. Key pattern: @file imports
  10. Hooks
  11. What are hooks?
  12. Why create hooks?
  13. Hook lifecycle events
  14. How to create a hook
  15. Agents
  16. What are agents?
  17. Agent file format
  18. Agent organization
  19. How agents interact with the system
  20. Marketplace / Plugin metadata ( marketplace.json )
  21. Commands ( .claude/commands/ )
  22. Creating a command
  23. Command ideas for engineers
  24. Skills
  25. What are skills?
  26. Progressive disclosure — 3 levels
  27. Skill file structure
  28. Skills resources
  29. MCP — Model Context Protocol
  30. What MCP is
  31. Transport types
  32. Usage example
  33. MCP registries
  34. MCP vs Skills vs Plugins
  35. Plugins — Deep Dive
  36. Anatomy of a plugin
  37. Installing plugins
  38. Why plugins win most of the time
  39. feature-dev Plugin
  40. Install
  41. How it works
  42. The 3 sub-agents
  43. Usage patterns
  44. feature-dev + Jira + GitHub MCP: the full pipeline
  45. GSD — Get Shit Done Plugin
  46. Install
  47. What GSD does differently
  48. When to use GSD
  49. GSD vs Ralph Loop
  50. YOLO Mode
  51. Ralph Loops
  52. What is a Ralph Loop?
  53. Real result
  54. Usage
  55. Karpathy's Level 5 Loop
  56. Multi-Agent Swarms
  57. Patterns of orchestration
  58. Dispatching parallel agents
  59. Plan → Agent → Review cycle
  60. Debugging Strategy
  61. The 5-step method
  62. Rules
  63. Prompting Patterns That Work
  64. Reading docs before coding
  65. Running tests and cleanup
  66. Comprehensive code review
  67. Addressing issues from a review
  68. Feature-dev via Jira + PR
  69. Bulk yes to follow-ups
  70. Full Workflow: Jira → main
  71. Sub Agents
  72. OpenAI Codex CLI
  73. Running agents from Claude Code
  74. Building a Real Project with Elixir + Claude Code
  75. What we're building
  76. Why Elixir is excellent for this
  77. Step 0 — Bootstrap the project
  78. Step 1 — Database schema
  79. Step 2 — Market data (the real-time engine)
  80. Step 3 — Portfolio context
  81. Step 4 — LiveView (the UI backbone)
  82. Step 5 — LLM integration
  83. Step 6 — Frontend (JS hooks + Tailwind)
  84. Step 7 — Docker + start scripts
  85. Step 8 — Tests
  86. The full build flow with Claude Code
  87. Elixir-specific commands to create
  88. Key Elixir gotchas Claude handles well
  89. End result
  90. Resources
  91. Official
  92. Community
  93. Quick Reference Card

Vibe Engineering with Claude Code

The Engineer's Field Guide to AI-Assisted Development

"We use LLMs, but we are responsible for the quality, delivery, and making sure it works."Simon Willison on Vibe Engineering


Table of Contents

  1. The 6 Levels of AI Autonomy
  2. Installation
  3. Claude Code Commands
  4. Sessions, Checkpoints & Git
  5. CLAUDE.md — The Project Brain
  6. Hooks
  7. Agents
  8. Commands (.claude/commands/)
  9. Skills
  10. MCP — Model Context Protocol
  11. MCP vs Skills vs Plugins
  12. Plugins — Deep Dive
  13. feature-dev Plugin
  14. GSD — Get Shit Done Plugin
  15. YOLO Mode
  16. Ralph Loops
  17. Multi-Agent Swarms
  18. Debugging Strategy
  19. Prompting Patterns That Work
  20. Building a Real Project with Elixir + Claude Code
  21. Resources

The 6 Levels of AI Autonomy

Each level unlocks the same principle: give the AI more autonomy over the loop.

graph TD
    L1["Level 1 — Permission Skipping\nRemove permission prompts.\nSeems advanced. It's the baseline."]
    L2["Level 2 — Context Management\nManage the window: /clear, /compact.\nDon't let the AI forget what you asked."]
    L3["Level 3 — Subagents\nEach task runs in its own context.\nAI works 2h alone without freezing."]
    L4["Level 4 — Continuous Loop\nAI tries to stop → system blocks exit → feeds the task back.\nOne dev ran 27h straight: 84 tasks completed."]
    L5["Level 5 — Structured Loop with Metrics\nKarpathy: 630-line script, went to sleep,\nwoke up with 100+ ML experiments done.\nLoop = measure → execute → analyze → improve."]
    L6["Level 6 — Remote Autonomous Agent\nDeploy to a server. Close the laptop.\nAI runs 24/7 connected to email, git, calendar."]

    L1 --> L2 --> L3 --> L4 --> L5 --> L6

    style L1 fill:#1a1a2e,color:#ecad0a,stroke:#209dd7
    style L2 fill:#1a1a2e,color:#ecad0a,stroke:#209dd7
    style L3 fill:#1a1a2e,color:#ecad0a,stroke:#209dd7
    style L4 fill:#1a1a2e,color:#753991,stroke:#ecad0a
    style L5 fill:#1a1a2e,color:#753991,stroke:#ecad0a
    style L6 fill:#1a1a2e,color:#209dd7,stroke:#753991
Level Name Key Idea
1 Permission Skipping Remove friction, not a feature
2 Context Management /clear, /compact, structured docs
3 Subagents Parallel isolated contexts
4 Continuous Loop Ralph Loop — AI keeps working
5 Structured Loop Metric-driven iterative improvement
6 Remote Autonomous AI lives on a server, not your laptop

Installation

# Terminal (npm)
npm install -g @anthropic-ai/claude-code
# Or via brew
brew install claude-code
# Verify
claude --version

VS Code Extension:

  • Open VS Code → Extensions (Cmd+Shift+X)
  • Search Claude Code → Install
  • Or press Cmd+Shift+PClaude Code: Open

Claude Code Commands

Use these slash commands inside the Claude Code terminal session.

Command What it does
/init Bootstraps CLAUDE.md for the current project — sets context for future sessions
/context Shows what's currently loaded in the context window
/compact Compresses the conversation history to free up context space
/clear Resets everything — fresh slate, empty context
/status Shows connection status, model, token usage
/model Switch or check the current model
/config Open settings (theme, model, behavior)
/stats Token usage stats for current session
/rewind Rewind to the previous checkpoint inside the session
/mcp Manage MCP server connections

Keyboard Shortcuts

Shortcut Action
Shift+Tab Enter Plan Mode — forces deeper reasoning before coding (uses Opus for planning, Sonnet for coding)
Ctrl+O Script/details mode

Plan Mode tip: Use it for complex tasks. Claude will think in claude-opus-4-6 before coding in claude-sonnet-4-6.

# settings stored here:
~/.claude/settings.local.json # allow commands to run automatically

Sessions, Checkpoints & Git

graph LR
    subgraph "Claude Code Internal"
        S["Session\n(resume)\nHigh-level state\nPick up where you left off"]
        C["Checkpoint\n(rewind)\nFine-grained\nGo back to a specific moment"]
    end
    subgraph "External — Always Reliable"
        G["Git Commits\nDurable history\nThe source of truth"]
    end
    S -->|contains many| C
    C -.->|parallel to| G

    style S fill:#1a1a2e,color:#ecad0a,stroke:#209dd7
    style C fill:#1a1a2e,color:#753991,stroke:#ecad0a
    style G fill:#1a1a2e,color:#209dd7,stroke:#753991
Concept Granularity Use when
Session (resume) High-level Working across multiple days
Checkpoint (rewind) Fine-grained step Undo a specific moment in current session
Git commit Permanent Always — the safest net

Personal workflow recommendation:

Git commits + occasional /rewind + Markdown progress files
Sessions reserved for multi-day work

CLAUDE.md — The Project Brain

CLAUDE.md is read automatically at session start. It's your persistent instructions to Claude.

# CLAUDE.md
## Project Overview
@docs/PLAN.md ← reference external docs with @
## Agents
@AGENTS.md ← agent definitions and responsibilities
## Rules
- Work in small increments; validate each step
- Use current APIs only
- No over-engineering
- Find root cause BEFORE fixing
- No emojis in code, logs, or prints
- Keep README.md concise

Key pattern: @file imports

## DETAILED PLAN
@docs/PLAN.md
## AGENTS
@AGENTS.md

Files referenced with @ are loaded into context automatically — keep them focused.


Hooks

What are hooks?

Hooks are shell commands that Claude Code executes automatically in response to lifecycle events — not Claude, the harness. They run regardless of what Claude decides to do.

Why create hooks?

  • Automate repetitive post-step work (code review, lint, notify)
  • Enforce consistency across every session
  • Trigger agents automatically without prompting

Hook lifecycle events

Event When it fires
Stop After Claude finishes a response/task
PreToolUse Before a tool is called
PostToolUse After a tool completes
Notification On notifications

How to create a hook

Add to .claude/settings.json:

{
"hooks": {
"Stop": {
"hooks": [
{
"type": "command",
"command": "claude agents run reviewer"
}
]
}
}
}

What this does: Every time Claude stops, it automatically runs the reviewer agent.

Use /update-config skill to configure hooks via the settings harness.


Agents

What are agents?

Agents are specialized Claude instances with a focused role, defined in .claude/agents/.

Agent file format

---
name: reviewer
description: This custom agent reviews code changes and provides feedback.
---
You review the file planning/PLAN.md AND write your feedback to planning/REVIEW.md

Agent organization

.claude/
agents/
reviewer.md ← code review agent
tester.md ← test runner agent
debugger.md ← debugging specialist

How agents interact with the system

sequenceDiagram
    participant U as User
    participant C as Claude Code
    participant H as Hook (Stop)
    participant A as Reviewer Agent
    participant F as planning/REVIEW.md

    U->>C: Implements feature
    C->>C: Writes code
    C-->>H: Fires Stop event
    H->>A: claude agents run reviewer
    A->>F: Reads PLAN.md + changed files
    A->>F: Writes feedback to REVIEW.md
    F-->>U: Review ready to read

Marketplace / Plugin metadata (marketplace.json)

{
"name": "independent-reviewer",
"owner": {
"name": "Your Name",
"email": "you@example.com"
},
"plugin": {
"version": "0.1.0",
"description": "Runs an independent code reviewer agent after each run."
}
}

Commands (.claude/commands/)

Commands are slash commands you define yourself. They're markdown files with $ARGUMENTS as the placeholder.

Creating a command

.claude/
commands/
doc-review.md
oban-debug.md
ship-checklist.md

.claude/commands/doc-review.md:

Review the documentation file in the planning folder called $ARGUMENTS
and add questions, clarifications or feedback to a new section at the end,
along with any opportunities to simplify.

Usage:

/doc-review PLAN.md
/doc-review MARKET_INTERFACE.md

Command ideas for engineers

Development workflow
/test-runner — auto-run tests after edits, summarize failures
/mix-check — compile + credo + dialyzer in one shot
/pr-review — review open PRs against a checklist
Elixir-specific
/oban-debug — query failed Oban jobs, surface error patterns
/ecto-query — slow query → suggest indexes and rewrites
/live-view — scaffold a LiveView component with standard patterns
Ship / Product
/ship-checklist — migration safety, rollback plan, feature flag check
/changelog — user-facing changelog from recent git commits
/customer-email — draft outreach from bullet points
Cross-cutting
/postmortem — structured postmortem from incident description
/adr — Architecture Decision Record from short description

Skills

What are skills?

Skills are markdown-first instructions that give Claude specialized expertise. They use progressive disclosure so Claude only loads what's needed.

Progressive disclosure — 3 levels

graph TD
    M["Level 1: Metadata\nname + description\nWhen should this fire?"]
    I["Level 2: Instructions\nWorkflows, guidance, code snippets"]
    R["Level 3: Resources + Code\nFiles, data, scripts to run"]

    M --> I --> R

    style M fill:#209dd7,color:#0d1117
    style I fill:#753991,color:#fff
    style R fill:#ecad0a,color:#0d1117

Skill file structure

.claude/
skills/
my-skill/
SKILL.md ← metadata + instructions
more_context.md ← extended docs
scripts/
helper.py ← scripts in any language

SKILL.md format:

---
name: cerebras-inference
description: Use this to call an LLM via LiteLLM and OpenRouter with Cerebras
---
# Calling an LLM via Cerebras
## Setup
OPENROUTER_API_KEY must be set in .env
uv add litellm pydantic
## Imports
from litellm import completion
MODEL = "openrouter/openai/gpt-oss-120b"
EXTRA_BODY = {"provider": {"order": ["cerebras"]}}
## Text response
response = completion(model=MODEL, messages=messages, reasoning_effort="low", extra_body=EXTRA_BODY)
result = response.choices[0].message.content
## Structured output
response = completion(model=MODEL, messages=messages, response_format=MyModel, reasoning_effort="low", extra_body=EXTRA_BODY)
result_as_object = MyModel.model_validate_json(response.choices[0].message.content)

Skills resources


MCP — Model Context Protocol

What MCP is

graph LR
    H["MCP Host\n(Claude Code)"]
    C["MCP Client\n(inside host)"]
    S1["MCP Server\n(Atlassian)"]
    S2["MCP Server\n(GitHub)"]
    S3["MCP Server\n(Your tools)"]

    H --> C
    C <--> S1
    C <--> S2
    C <--> S3

    style H fill:#1a1a2e,color:#ecad0a,stroke:#209dd7
    style C fill:#1a1a2e,color:#209dd7,stroke:#209dd7
    style S1 fill:#1a1a2e,color:#753991,stroke:#753991
    style S2 fill:#1a1a2e,color:#753991,stroke:#753991
    style S3 fill:#1a1a2e,color:#753991,stroke:#753991
MCP is MCP is not
A standard interface to connect LLMs to tools The tools themselves
Easy way to use tools someone else built A radical technical breakthrough
A "game-changer" because of ecosystem adoption Free context — overuse fills your window
Easy way to share your tools Automatically efficient

Transport types

Type Where server runs Notes
Local Your machine Can still call remote HTTP APIs
Remote SSE Cloud server Legacy transport
Streamable HTTP Cloud server Modern, preferred

Usage example

# Connect
/mcp
# Authentication successful. Reconnected to atlassian.
# Then just talk
"please carry out jira issue PL-2 and raise a PR with your changes"
"please merge the PR, switch the branch to main, mark PL-2 done in Jira"

MCP registries


MCP vs Skills vs Plugins

quadrantChart
    title Capability vs Setup Complexity
    x-axis Simple --> Complex Setup
    y-axis Low Capability --> High Capability
    quadrant-1 Power Users
    quadrant-2 Best Choice
    quadrant-3 Start Here
    quadrant-4 Overkill
    Plugins: [0.2, 0.7]
    Skills: [0.3, 0.6]
    MCP: [0.8, 0.9]
Plugins Skills MCP
Idea Bundle of MCP + skills + commands Markdown-first expertise/instructions Connect Claude to external tools
Setup Simplest — install and go Simple — write markdown Complex — run a server process
Context cost Low Low (progressive disclosure) Can be high
Flexibility Medium Medium Very high
Ecosystem Growing Growing Massive
Availability Claude Code only Claude Code + others Universal
Best for Starting out, bundled workflows Custom expertise, lightweight tools External system integrations

START HERE: Plugins. Most of the time, a plugin gives you the best trade-off of context, capability, and simplicity. Move to MCP only when you need an external system's tools.


Plugins — Deep Dive

A plugin is the highest-level construct in Claude Code. It bundles MCP servers, skills, commands, agents, and hooks into a single installable unit.

Anatomy of a plugin

my-plugin/
marketplace.json metadata (name, owner, version, description)
.claude/
agents/ specialized agents
commands/ slash commands
skills/ markdown skills
mcp/ MCP server(s) if needed

Installing plugins

/plugin install ralph-loop@claude-plugins-official
/plugin install feature-dev@claude-plugins-official
/plugin install gsd@claude-plugins-official

Why plugins win most of the time

graph TD
    Q{"What do you need?"}
    Q -->|"External tool\n(Jira, GitHub, DB)"| MCP["MCP Server"]
    Q -->|"Custom expertise\nor instructions"| SK["Skill"]
    Q -->|"Bundled workflow\nthat just works"| PL["Plugin ← Start Here"]
    Q -->|"Automate after\nevery Claude stop"| HK["Hook"]

    style PL fill:#ecad0a,color:#0d1117
    style MCP fill:#1a1a2e,color:#209dd7,stroke:#209dd7
    style SK fill:#1a1a2e,color:#753991,stroke:#753991
    style HK fill:#1a1a2e,color:#fff,stroke:#888

feature-dev Plugin

feature-dev is a structured multi-agent plugin that orchestrates the full feature development lifecycle — from understanding the codebase to shipping reviewed code.

Install

/plugin install feature-dev@claude-plugins-official

How it works

sequenceDiagram
    participant U as You
    participant E as code-explorer
    participant A as code-architect
    participant D as Developer (Claude)
    participant R as code-reviewer

    U->>E: /feature-dev:feature-dev "implement X"
    E->>E: Trace execution paths\nMap architecture layers\nFind dependencies
    E->>A: Here's what exists
    A->>A: Design feature architecture\nIdentify files to create/modify\nPlan data flow
    A->>D: Here's the blueprint
    D->>D: Implement following conventions
    D->>R: Here's the diff
    R->>U: Feedback + approval

The 3 sub-agents

Agent Role What it does
code-explorer Understand Traces execution paths, maps architecture, documents dependencies
code-architect Design Designs feature architecture matching existing patterns, produces implementation blueprint
code-reviewer Review Reviews for bugs, logic errors, security issues, adherence to conventions

Usage patterns

# Basic feature implementation
/feature-dev:feature-dev please implement jira issue PL-3 with a NextJS
application in a directory called frontend, then raise a PR when done
# With full test coverage + code review
/feature-dev:feature-dev please implement user authentication,
add extensive automated tests and manual tests,
and have the code-review agents do the review
# The "yes to all" power move — answer follow-ups in bulk
"yes to all 3 - please add extensive automated tests and manual tests,
and have the code-review agents do the review"

feature-dev + Jira + GitHub MCP: the full pipeline

# Step 1 — Connect
/mcp
# → Authentication successful
# Step 2 — Implement from ticket
/feature-dev:feature-dev please carry out jira issue PL-2 and raise a PR
# Step 3 — Merge and close
"please merge the PR locally, push to main, mark PL-2 done in Jira"

GSD — Get Shit Done Plugin

GSD is the most opinionated plugin in the official collection. It's designed for one thing: shipping.

It removes friction from the entire loop — plan → implement → test → commit — and keeps Claude working until the task is done or it explicitly can't proceed.

Install

/plugin install gsd@claude-plugins-official

What GSD does differently

graph LR
    N["Normal Claude"]
    G["GSD Claude"]

    N --> N1["Asks for clarification"]
    N --> N2["Stops to confirm changes"]
    N --> N3["Waits for approval"]

    G --> G1["Makes reasonable assumptions\nand ships"]
    G --> G2["Commits as it goes"]
    G --> G3["Keeps working until DONE"]

    style G fill:#ecad0a,color:#0d1117
    style N fill:#1a1a2e,color:#888,stroke:#444
    style G1 fill:#1a1a2e,color:#ecad0a,stroke:#ecad0a
    style G2 fill:#1a1a2e,color:#ecad0a,stroke:#ecad0a
    style G3 fill:#1a1a2e,color:#ecad0a,stroke:#ecad0a

When to use GSD

Use GSD when... Don't use GSD when...
You have a well-defined task The scope is unclear
You trust the codebase is stable You're in a sensitive production env
You want maximum throughput You need fine-grained control of each step
Prototyping / building fast Critical path code needs review

GSD vs Ralph Loop

GSD Ralph Loop
Focus Ship the task Iterate until improved
Exit condition Task complete Max iterations or signal
Best for Well-scoped features Open-ended improvement
Interruption Minimal — it ships Structured per iteration

Practical rule: Use GSD when you know what you want. Use Ralph when you want Claude to figure it out iteratively.


YOLO Mode

Skip all permission prompts. Claude acts without asking for approval.

# Real YOLO mode (for the brave)
claude --dangerously-skip-permissions

Use with caution. Good for trusted automated pipelines. Never use in a shared environment.

Safer alternative: allow specific commands in settings.local.json:

{
"allowedCommands": ["mix test", "mix compile", "git status"]
}

Ralph Loops

What is a Ralph Loop?

A continuous iteration pattern: Claude works on a task, would normally stop, but the system feeds the task back and Claude keeps going until a completion signal or max iterations.

stateDiagram-v2
    [*] --> Working: Start task
    Working --> Done: Completion signal
    Working --> Blocked: Claude tries to stop
    Blocked --> Working: System feeds task back
    Done --> [*]

    note right of Blocked
        "DONE" keyword
        or max-iterations reached
        breaks the loop
    end note

Real result

One developer ran 27 hours straight with a Ralph Loop — 84 tasks completed.

Usage

# Install
/plugin install ralph-loop@claude-plugins-official
# Run
/ralph-loop:ralph-loop "Please significantly improve this project.
Add user management, multiple kanban boards per user, and other features
to build a comprehensive project management application,
testing thoroughly as you go and maintaining strong test coverage
and good integration tests" --max-iterations 10

Karpathy's Level 5 Loop

Karpathy published a 630-line script, went to sleep, and woke up with 100+ ML experiments completed.

The pattern:

Loop:
1. Define metric
2. Execute experiment
3. Analyze results
4. Improve hypothesis
5. Repeat until max iterations or goal met

Multi-Agent Swarms

Patterns of orchestration

graph TD
    subgraph "Sequential (Pipeline)"
        A1[Agent 1: Plan] --> A2[Agent 2: Implement] --> A3[Agent 3: Review]
    end

    subgraph "Parallel (Swarm)"
        O[Orchestrator]
        O --> B1[Agent: Feature A]
        O --> B2[Agent: Feature B]
        O --> B3[Agent: Tests]
        B1 --> M[Merge Results]
        B2 --> M
        B3 --> M
    end

    subgraph "Loop (Ralph/Continuous)"
        C1[Agent] --> C2{Done?}
        C2 -->|No| C1
        C2 -->|Yes| C3[Output]
    end

    style O fill:#ecad0a,color:#0d1117
    style M fill:#209dd7,color:#0d1117
Pattern When to use Risk
Sequential Tasks with dependencies, reviews after code Low — ordered, predictable
Parallel Swarm Independent features, research tasks Medium — merge conflicts possible
Ralph Loop Iterative improvement, long autonomous runs High — needs clear exit condition

Dispatching parallel agents

# Claude Code skill
/superpowers:dispatching-parallel-agents
# Prompt pattern:
"Please work on these 3 independent tasks in parallel:
1. Implement the user auth module
2. Write the database migrations
3. Create the API documentation"

Plan → Agent → Review cycle

sequenceDiagram
    participant P as PLAN.md
    participant O as Orchestrator (Claude)
    participant A1 as feature-dev agent
    participant A2 as code-reviewer agent
    participant G as Git

    P->>O: Read requirements
    O->>A1: Implement feature X
    A1->>G: Commit changes
    A1->>O: Done
    O->>A2: Review changes
    A2->>P: Write feedback to REVIEW.md
    A2->>O: Approved / changes needed
    O->>G: Merge or iterate

Debugging Strategy

The 5-step method

flowchart LR
    S["1. Snapshot\ngit commit\n(safe point)"] --> T["2. Paste Trace\nDrop stack trace\ninto chat"]
    T --> R["3. Reproduce\nConfirm consistent\nreproduction"]
    R --> H["4. Hypothesize\nInvestigate + form\nhypotheses"]
    H --> F["5. Fix & Prove\nDemonstrate root cause\nFix + verify\nLog in CLAUDE.md"]

    style S fill:#ecad0a,color:#0d1117
    style T fill:#209dd7,color:#0d1117
    style R fill:#1a1a2e,color:#fff,stroke:#209dd7
    style H fill:#1a1a2e,color:#fff,stroke:#753991
    style F fill:#753991,color:#fff

Rules

  1. Always identify root cause before fixing — no guessing
  2. Prove the problem first — evidence before assertions
  3. One test at a time — be methodical
  4. No blind workarounds
  5. Capture lessons in CLAUDE.md

Use skill: /superpowers:systematic-debugging


Prompting Patterns That Work

Reading docs before coding

please read PLAN.md in the docs folder to understand everything that's been
built so far, and any supporting docs

Running tests and cleanup

please run all tests to confirm that everything is working,
bringing up the server as needed and bringing down the server at the end

Comprehensive code review

please carry out a comprehensive code review of the entire repo,
and write a report with actions to code_review.md in the docs folder

Addressing issues from a review

OK thank you, please go ahead and address all the Critical, High and Medium
priority issues and retest everything and let me know when everything is
remediated and tests are OK

Feature-dev via Jira + PR

/feature-dev:feature-dev please implement jira issue PL-3 with a NextJS
application in a directory called frontend, then raise a PR when done

Bulk yes to follow-ups

yes to all 3 please add extensive automated tests and manual tests,
and have the code-review agents do the review

Full Workflow: Jira → main

graph LR
    J["Jira Issue\nPL-2"] -->|/mcp| MC["Atlassian MCP\nRead ticket"]
    MC --> FD["/feature-dev\nImplement"]
    FD --> PR["GitHub MCP\nRaise PR"]
    PR --> MG["Merge + push main"]
    MG --> JD["Jira: Done"]

    style J fill:#0052CC,color:#fff
    style MC fill:#1a1a2e,color:#ecad0a,stroke:#209dd7
    style FD fill:#1a1a2e,color:#209dd7,stroke:#753991
    style PR fill:#24292e,color:#fff
    style MG fill:#28a745,color:#fff
    style JD fill:#0052CC,color:#fff

Prompts used:

/mcp
# → Authentication successful. Reconnected to atlassian.
"please carry out jira issue PL-2 and raise a PR with your changes"
# → Status: Metamorphosing...
"please merge the PR locally and push to main, mark PL-2 done in Jira"
# → Done. PR merged, branch switched to main, Jira updated.

Sub Agents

OpenAI Codex CLI

# Install
npm install -g @openai/codex
# Documentation
# https://developers.openai.com/codex/cli

Running agents from Claude Code

# Run a named agent
claude agents run reviewer
# Run with arguments
claude agents run doc-reviewer -- PLAN.md

Building a Real Project with Elixir + Claude Code

This section walks through how to vibe-engineer a production-quality full-stack Elixir app — an AI-powered trading workstation — entirely with Claude Code. Same approach works for any Phoenix/LiveView project.

What we're building

FinAlly AI Trading Workstation
├── Phoenix LiveView (real-time UI, zero JS framework)
├── PostgreSQL + Ecto (migrations, typed schemas)
├── Oban (background jobs: market data, snapshots)
├── Phoenix.PubSub (price ticks all connected browsers)
├── LLM chat (OpenRouter Cerebras, structured JSON output)
└── Docker Compose (single command to run everything)

Why Elixir is excellent for this

Decision Why
LiveView Full-stack Elixir — no REST/CORS, real-time diffs over one WebSocket
PubSub Native fan-out to all connected LiveViews, zero extra infra
Oban Persistent job queue backed by Postgres — handles retries and scheduling
OTP/GenServer Fault-tolerant processes, supervised restarts, built-in concurrency
Ecto migrations Reproducible schema — always version-controlled, never ad-hoc SQL

Step 0 — Bootstrap the project

"Create a new Phoenix 1.7 project called finnaly_ex with LiveView,
Ecto/Postgres, and no mailer. Set up a docker-compose.yml with a
postgres:16-alpine service and an app service on port 4000.
Create a .env.example with OPENROUTER_API_KEY and MASSIVE_API_KEY.
Add a CLAUDE.md that captures the architecture decisions."

CLAUDE.md essentials for any Elixir project:

# CLAUDE.md
## Rules
- Work in small increments; run mix test after each change
- Never edit existing migrations — always create a new one
- Use Ecto.Multi for multi-step DB operations
- All business logic lives in contexts (lib/finnaly_ex/)
- Web layer (lib/finnaly_ex_web/) has zero business logic
- Use timestamps() macro in all Ecto schemas
- Run: mix compile --warnings-as-errors before committing
- No floating point for money — use integer cents or the Money library
## Commands
- mix ecto.setup — create DB + migrate + seed
- mix test — run all tests
- mix phx.server — start dev server

Step 1 — Database schema

"Create Ecto migrations and schema modules for:
- user_profiles (id string pk, cash_balance float, timestamps)
- watchlist_entries (binary_id pk, user_id string, ticker string, unique index on user_id+ticker, timestamps)
- positions (binary_id pk, user_id string, ticker string, quantity float, avg_cost float, timestamps)
- trades (binary_id pk, user_id, ticker, side string, quantity float, price float, executed_at utc_datetime, timestamps)
- portfolio_snapshots (binary_id pk, user_id, total_value float, recorded_at utc_datetime, timestamps)
- chat_messages (binary_id pk, user_id, role string, content string, actions map, timestamps)
Seed the default user with $10,000 cash and 10 watchlist tickers: AAPL GOOGL MSFT AMZN TSLA NVDA META JPM V NFLX"

What good output looks like:

# priv/repo/migrations/20260101000001_create_positions.exs
def change do
create table(:positions, primary_key: false) do
add :id, :binary_id, primary_key: true
add :user_id, :string, null: false, default: "default"
add :ticker, :string, null: false
add :quantity, :float, null: false
add :avg_cost, :float, null: false
timestamps()
end
create unique_index(:positions, [:user_id, :ticker])
end

Step 2 — Market data (the real-time engine)

graph LR
    E["Env var check\n(runtime.exs)"]
    E -->|MASSIVE_API_KEY set| MW["MassiveWorker\n(Oban, 15s poll)"]
    E -->|not set| SW["SimulatorWorker\n(Oban, 500ms GBM)"]
    MW --> PC["PriceCache\n(ETS table)"]
    SW --> PC
    PC --> PS["Phoenix.PubSub\nbroadcast 'prices'"]
    PS --> LV["LiveView\nassigns update"]
    LV --> BR["Browser DOM diff\n(price flash)"]

    style E fill:#ecad0a,color:#0d1117
    style PC fill:#1a1a2e,color:#209dd7,stroke:#209dd7
    style PS fill:#1a1a2e,color:#753991,stroke:#753991

Prompt:

"Implement the market data context in lib/finnaly_ex/market_data/.
Create a PriceCache module backed by ETS that stores latest price,
previous price, and timestamp per ticker.
Create SimulatorWorker (Oban job) that uses geometric Brownian motion
to generate prices for all watched tickers every 500ms,
writes to PriceCache, and broadcasts {:price_update, ticker, price_data}
on Phoenix.PubSub topic 'prices'.
The worker should be self-rescheduling: after each run, enqueue the next
job with scheduled_at: DateTime.add(now, 500, :millisecond).
Use a single job that updates all tickers per run."

Step 3 — Portfolio context

"Implement lib/finnaly_ex/portfolio/portfolio.ex with:
- execute_trade/3 (user_id, %{ticker, side, quantity}) — market order at
current PriceCache price, validates sufficient cash for buys and
sufficient shares for sells, upserts positions, logs to trades table,
records a portfolio snapshot via Ecto.Multi
- get_positions/1 (user_id) — returns positions with current price from
PriceCache and unrealized P&L calculated
- get_portfolio_value/1 (user_id) — sum of (quantity * current_price) + cash
Write ExUnit tests for: buy, sell, insufficient cash, oversell edge cases."

Step 4 — LiveView (the UI backbone)

"Create TradingLive in lib/finnaly_ex_web/live/trading_live.ex.
On mount: subscribe to Phoenix.PubSub 'prices', load watchlist,
positions, cash, recent portfolio snapshots, recent chat messages.
Handle these events:
- 'trade' %{ticker, quantity, side} → Portfolio.execute_trade
- 'add_ticker' %{ticker} → Watchlist.add
- 'remove_ticker' %{ticker} → Watchlist.remove
- 'select_ticker' %{ticker} → update :selected_ticker assign
- 'send_message' %{content} → enqueue LLMWorker Oban job, set :loading true
On handle_info {:price_update, ticker, data}: update prices assign,
accumulate sparkline data per ticker (list of last 60 prices).
On handle_info {:llm_response, message}: update chat assigns, clear :loading."

The critical insight — sparklines for free:

# In handle_info — no API call, just accumulate from PubSub ticks
def handle_info({:price_update, ticker, price_data}, socket) do
sparklines = Map.update(
socket.assigns.sparklines,
ticker,
[price_data.price],
fn existing -> Enum.take([price_data.price | existing], 60) end
)
{:noreply, assign(socket, prices: ..., sparklines: sparklines)}
end

Step 5 — LLM integration

"Implement lib/finnaly_ex/chat/llm_worker.ex as an Oban job.
On perform/1:
1. Load portfolio context (cash, positions with P&L, watchlist + prices)
2. Load last 20 chat messages from DB
3. POST to https://openrouter.ai/api/v1/chat/completions via Req with:
- model: 'cerebras/llama-3.3-70b'
- response_format: %{type: 'json_object'}
- system prompt: FinAlly trading assistant, always respond with JSON
matching schema: {message, trades: [{ticker, side, quantity}],
watchlist_changes: [{ticker, action}]}
4. Parse and validate JSON response
5. Auto-execute any trades via Portfolio.execute_trade
6. Apply any watchlist changes via Watchlist context
7. Persist assistant message + actions to chat_messages
8. Broadcast {:llm_response, message} on PubSub so LiveView updates
If the job fails (network error, parse error), broadcast {:llm_error, reason}
so the LiveView clears :loading and shows the error inline.
Add LLM_MOCK=true support that returns a deterministic mock response."

Step 6 — Frontend (JS hooks + Tailwind)

"Set up assets/js/hooks/ with two Phoenix JS hooks:
1. PriceFlash: watches the data-price attribute on price elements.
When it changes, toggle 'price-up' or 'price-down' CSS class
(green or red background) that fades over 500ms via Tailwind transition.
2. Chart: mounts Lightweight Charts on phx:mounted using data-series attribute.
On phx:updated, push new data points to the existing chart instance.
Destroy chart on phx:destroyed.
In app.css, configure Tailwind with dark theme:
background: #0d1117, borders: muted gray, accent: #ecad0a,
primary: #209dd7, secondary: #753991.
Create a dense terminal-style layout: watchlist panel left,
main chart center, portfolio heatmap + P&L chart right,
positions table bottom, AI chat panel as right sidebar,
trade bar as a compact strip above the positions table."

Step 7 — Docker + start scripts

"Create a multi-stage Dockerfile:
Stage 1 (elixir:1.17-otp-27-slim): mix deps.get --only prod,
mix assets.deploy (esbuild + tailwind), mix release
Stage 2 (debian:bookworm-slim): copy release, expose 4000,
CMD /app/bin/finnaly_ex start
Create docker-compose.yml with postgres:16-alpine (healthcheck) and app service.
Create scripts/start_mac.sh: docker compose up --build -d, print localhost:4000.
Create scripts/stop_mac.sh: docker compose down (keep pgdata volume).
Create config/runtime.exs reading DATABASE_URL, SECRET_KEY_BASE,
OPENROUTER_API_KEY, MASSIVE_API_KEY from environment."

Step 8 — Tests

"Write the full test suite:
- test/finnaly_ex/portfolio_test.exs: buy, sell, P&L, edge cases
- test/finnaly_ex/market_data/simulator_worker_test.exs: valid GBM prices
- test/finnaly_ex_web/live/trading_live_test.exs using Phoenix.LiveViewTest:
render mount shows watchlist tickers, trade event updates assigns,
price_update PubSub message changes data-price attribute,
send_message with LLM_MOCK=true shows mock response
Run mix test. Fix any failures before moving on."

The full build flow with Claude Code

sequenceDiagram
    participant Y as You
    participant C as Claude Code
    participant G as Git
    participant D as Docker

    Y->>C: Step 0 — Bootstrap + CLAUDE.md
    C->>G: git commit "initial phoenix setup"
    Y->>C: Step 1 — DB migrations + seeds
    C->>C: mix ecto.setup → verify
    C->>G: git commit "add schema migrations"
    Y->>C: Step 2 — Market data + PriceCache
    C->>C: mix test → all pass
    C->>G: git commit "market data engine"
    Y->>C: Step 3 — Portfolio context
    C->>C: mix test → all pass
    C->>G: git commit "portfolio context"
    Y->>C: Step 4 — LiveView
    C->>C: mix test → LiveView tests pass
    C->>G: git commit "trading LiveView"
    Y->>C: Step 5 — LLM integration
    C->>C: LLM_MOCK=true mix test
    C->>G: git commit "LLM chat worker"
    Y->>C: Step 6 — Frontend
    C->>D: docker compose up --build
    Y->>Y: Open localhost:4000 ✓
    C->>G: git commit "frontend + JS hooks"

Elixir-specific commands to create

.claude/commands/
mix-check.mdmix compile --warnings-as-errors && mix credo && mix dialyzer
test-runner.mdmix test --trace, summarize failures
oban-debug.mdquery failed Oban jobs and surface error patterns
ecto-query.mdgiven slow query, suggest indexes and rewrites
live-view.mdscaffold a LiveView with standard patterns
ship-checklist.mdmigration safety, rollback plan, env vars set?

.claude/commands/mix-check.md:

Run mix compile --warnings-as-errors && mix credo --strict && mix test
Report all warnings, Credo violations, and test failures.
Group issues by severity. Suggest fixes for each.

Key Elixir gotchas Claude handles well

Gotcha What to tell Claude
Floating point money drift "Use integer cents or the Money library, never bare floats for financial values"
Migration immutability "Never edit existing migrations — always create a new migration file"
PubSub subscription in tests "Use Phoenix.PubSub.subscribe in test setup, not in LiveView mount"
Oban in tests "Set Oban.Testing mode in test config, use perform_job/2 directly"
LiveView assigns atomicity "Always use assign/3 or assign_new/3, never mutate socket.assigns directly"
N+1 in Ecto "Preload associations in context functions, never in LiveView or templates"

End result

One docker compose up --build command. Browser opens. You see:

  • Live-ticking prices flashing green/red
  • $10,000 virtual cash
  • Sparklines filling in from PubSub ticks
  • A chat panel where you type "buy 10 shares of AAPL" and it executes

Built entirely by Claude Code, owned entirely by you.


Resources

Official

Community

Resource URL
Skills marketplace https://skills.sh
MCP discovery https://mcp.so
AI tools https://glamma.ai
Manual NDA plugin example http://github.com/CommonPaper/Manual-NDA
Vibe Engineering article https://simonwillison.net/2025/Oct/7/vibe-engineering

Quick Reference Card

SETUP
npm install -g @anthropic-ai/claude-code
/init → creates CLAUDE.md
DAILY COMMANDS
/clear → fresh context
/compact → compress history
/rewind → undo last step
Shift+Tab → plan mode (think before code)
EXTENSIONS
Plugins → start here (simplest)
Skills → custom expertise (markdown)
MCP → external tools (complex but powerful)
AUTONOMY LADDER
YOLO → --dangerously-skip-permissions
Ralph → /ralph-loop ... --max-iterations N
Remote → deploy to server, runs 24/7
GOLDEN RULES
✓ Read PLAN.md before coding
✓ Git commit before chaos
✓ Root cause before fix
✓ You own the quality, not the AI

Last updated: 2026-04-01 — Built with Claude Code