In this article
- The Engineer's Field Guide to AI-Assisted Development
- Table of Contents
- The 6 Levels of AI Autonomy
- Installation
- Claude Code Commands
- Keyboard Shortcuts
- Sessions, Checkpoints & Git
- CLAUDE.md — The Project Brain
- Key pattern: @file imports
- Hooks
- What are hooks?
- Why create hooks?
- Hook lifecycle events
- How to create a hook
- Agents
- What are agents?
- Agent file format
- Agent organization
- How agents interact with the system
- Marketplace / Plugin metadata ( marketplace.json )
- Commands ( .claude/commands/ )
- Creating a command
- Command ideas for engineers
- Skills
- What are skills?
- Progressive disclosure — 3 levels
- Skill file structure
- Skills resources
- MCP — Model Context Protocol
- What MCP is
- Transport types
- Usage example
- MCP registries
- MCP vs Skills vs Plugins
- Plugins — Deep Dive
- Anatomy of a plugin
- Installing plugins
- Why plugins win most of the time
- feature-dev Plugin
- Install
- How it works
- The 3 sub-agents
- Usage patterns
- feature-dev + Jira + GitHub MCP: the full pipeline
- GSD — Get Shit Done Plugin
- Install
- What GSD does differently
- When to use GSD
- GSD vs Ralph Loop
- YOLO Mode
- Ralph Loops
- What is a Ralph Loop?
- Real result
- Usage
- Karpathy's Level 5 Loop
- Multi-Agent Swarms
- Patterns of orchestration
- Dispatching parallel agents
- Plan → Agent → Review cycle
- Debugging Strategy
- The 5-step method
- Rules
- Prompting Patterns That Work
- Reading docs before coding
- Running tests and cleanup
- Comprehensive code review
- Addressing issues from a review
- Feature-dev via Jira + PR
- Bulk yes to follow-ups
- Full Workflow: Jira → main
- Sub Agents
- OpenAI Codex CLI
- Running agents from Claude Code
- Building a Real Project with Elixir + Claude Code
- What we're building
- Why Elixir is excellent for this
- Step 0 — Bootstrap the project
- Step 1 — Database schema
- Step 2 — Market data (the real-time engine)
- Step 3 — Portfolio context
- Step 4 — LiveView (the UI backbone)
- Step 5 — LLM integration
- Step 6 — Frontend (JS hooks + Tailwind)
- Step 7 — Docker + start scripts
- Step 8 — Tests
- The full build flow with Claude Code
- Elixir-specific commands to create
- Key Elixir gotchas Claude handles well
- End result
- Resources
- Official
- Community
- 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
- The 6 Levels of AI Autonomy
- Installation
- Claude Code Commands
- Sessions, Checkpoints & Git
- CLAUDE.md — The Project Brain
- Hooks
- Agents
- Commands (
.claude/commands/) - Skills
- MCP — Model Context Protocol
- MCP vs Skills vs Plugins
- Plugins — Deep Dive
- feature-dev Plugin
- GSD — Get Shit Done Plugin
- YOLO Mode
- Ralph Loops
- Multi-Agent Swarms
- Debugging Strategy
- Prompting Patterns That Work
- Building a Real Project with Elixir + Claude Code
- 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+P→Claude 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-6before coding inclaude-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-configskill 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
- http://registry.modelcontextprotocol.io
- https://mcp.so
- https://github.com/modelcontextprotocol/servers
- https://glamma.ai
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
- Always identify root cause before fixing — no guessing
- Prove the problem first — evidence before assertions
- One test at a time — be methodical
- No blind workarounds
- 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.md — mix compile --warnings-as-errors && mix credo && mix dialyzer
test-runner.md — mix test --trace, summarize failures
oban-debug.md — query failed Oban jobs and surface error patterns
ecto-query.md — given slow query, suggest indexes and rewrites
live-view.md — scaffold a LiveView with standard patterns
ship-checklist.md — migration 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
| Resource | URL |
|---|---|
| Claude Plugins (official) | http://github.com/anthropics/claude-plugins-official |
| Skills repo | https://github.com/anthropics/skills/ |
| MCP Registry | http://registry.modelcontextprotocol.io |
| MCP Servers (official) | https://github.com/modelcontextprotocol/servers |
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