Skip to content

Night Agent — Implementation

Current State

The night agent is an autonomous Claude Code session that runs unattended, typically overnight (KST). It works through a fixed 4-stage pipeline — bug triage, code review, feature development, and QA — then stops. It never pushes to remote.

The agent's operating instructions live in .claude/agent-prompt.md. This doc explains how it works from a human perspective; that file is the authoritative source of truth.

How It Works

Entry point

The agent is invoked by running Claude Code with .claude/agent-prompt.md as its system prompt. On startup it:

  1. Checks out main and runs git status
  2. Reads BACKLOG.md for full context
  3. Checks the current KST time — if 06:00 or later, it commits any in-progress work, appends an "auto-stopped" note to agent-log.html, and exits immediately

Stage 1 — Bug Triage

Runs pytest tests/ -x -q. If tests fail (or BACKLOG.md has items under ## Bugs), it:

  1. Identifies the domain from the stack trace
  2. Delegates the fix to the appropriate sub-agent (see Sub-agents below)
  3. Reviews the diff, commits on main (or a fix/<slug> branch for larger changes)
  4. Skips directly to Stage 4

Stage 2 — Code Review

Lists all agent/feat-* branches and reviews any that don't yet have a ## Review section in their agent-log.md. For each:

  • Reads the log and changed files
  • Checks correctness, convention compliance, edge cases, and test coverage
  • Appends a verdict (approve / request-changes / needs-discussion) to the branch's agent-log.md
  • If request-changes: adds the issues to ## Bugs in BACKLOG.md on main

Stage 3 — Feature Development

Picks the first unchecked [ ] item from BACKLOG.md ## Queue, moves it to ## In Progress, and creates a branch agent/feat-<slug>. Before delegating, it writes a pre-delegation plan covering which files change, key logic, and any spec gotchas. It then spawns the appropriate sub-agent, reviews the diff, writes agent-log.md to the branch, and commits.

If blocked (missing dependency, unclear spec, API key needed), it writes a Status: blocked log, moves the item back to Queue, and stops.

Stage 4 — QA

After any session that produced code changes, a test-engineer sub-agent runs the full test suite plus targeted checks (e.g. FEATURE_ORDER consistency for ML changes, dry-run fetch for scrapers). If QA fails, the agent spawns a fix sub-agent and re-runs QA before finishing.

Update main

After completing any stage, the agent:

  1. Updates BACKLOG.md (moves item to ## Completed with branch, date, SHA)
  2. Rebuilds agent-log.html with a new session card (stage run, changes, QA result, review verdicts)
  3. Commits: docs(agent): update log after <session-summary>

Sub-agents

The agent routes work to domain specialists based on the area touched:

Domain Sub-agent
Data / scraper / scheduler / news ingestion data-engineer
ML / sentiment / predictions / feature engineering ml-analyst
Dashboard / React / frontend / UI frontend-engineer
CI/CD / Makefile / Docker / deployment devops-engineer
Security / auth / API keys / permissions / RLS security-reviewer
Stack trace / crash / hard-to-reproduce bug debugger
Unclear claude (general)

Sub-agent definitions live in .claude/agents/.

Artifacts

File Purpose
BACKLOG.md Queue, in-progress, completed items; bug list
agent-log.html Human-readable session history with QA results and review verdicts
agent/feat-<slug>/agent-log.md Per-feature log written to the feature branch

Gotchas

  • One stage per session — if Stage 1 or Stage 2 produced real work, the agent stops after Stage 4 rather than continuing to Stage 3.
  • 06:00 KST hard stop — the agent checks the time at multiple points and aborts if it's past 06:00 KST.
  • Sub-agents don't touch git — all git operations (commit, branch creation, BACKLOG.md edits) are done by the orchestrating agent, not the sub-agents.
  • Never git add . — files are staged explicitly to avoid accidentally committing .env, .pkl, or .db files.

Constraints

  • Never pushes to remote
  • Never modifies .env
  • Never commits model_cache/*.pkl or *.db files
  • Commits are atomic — one logical change per commit