Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
# Template for podman-compose.yaml. Copy to `.env` and replace every secret.
# Generate strong values: `openssl rand -hex 32`
# cp .env.example .env

# --- Core infra secrets (override the # CHANGEME defaults in the compose) ---
POSTGRES_PASSWORD=postgres
CLICKHOUSE_PASSWORD=clickhouse
MINIO_ROOT_PASSWORD=miniosecret
REDIS_AUTH=myredissecret
SALT=mysalt
ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
NEXTAUTH_SECRET=mysecret
NEXTAUTH_URL=http://localhost:3000

# --- Headless initialization ---
# On first boot langfuse-web auto-creates this org/project/user and provisions
# the API keys below. No manual UI signup needed.
# Docs: https://langfuse.com/self-hosting/administration/headless-initialization
LANGFUSE_INIT_ORG_ID=case
LANGFUSE_INIT_ORG_NAME=Case
LANGFUSE_INIT_PROJECT_ID=case
LANGFUSE_INIT_PROJECT_NAME=Case
LANGFUSE_INIT_PROJECT_PUBLIC_KEY=pk-lf-00000000-0000-0000-0000-000000000000
LANGFUSE_INIT_PROJECT_SECRET_KEY=sk-lf-00000000-0000-0000-0000-000000000000
LANGFUSE_INIT_USER_EMAIL=admin@case.local
LANGFUSE_INIT_USER_NAME=Case Admin
LANGFUSE_INIT_USER_PASSWORD=changeme123

# --- Client config (the `ca` app reads these; match the INIT keys above) ---
LANGFUSE_HOST=http://localhost:3000
LANGFUSE_PUBLIC_KEY=pk-lf-00000000-0000-0000-0000-000000000000
LANGFUSE_SECRET_KEY=sk-lf-00000000-0000-0000-0000-000000000000
11 changes: 11 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,3 +24,14 @@ dist/

# bun artifacts
*.bun-build
.todos/

# Local secrets for podman-compose (use .env.example as the template)
.env
.sidecar/
.sidecar-agent
.sidecar-task
.sidecar-pr
.sidecar-start.sh
.sidecar-base
.td-root
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ Humans steer. Agents execute. When agents struggle, fix the harness.
Run the session command to gather context before doing anything else:

```bash
SESSION=$(ca session <target-repo-path> --task <task.json>)
SESSION=$(ca session <target-repo-path> --task <td-id>)
echo "$SESSION"
```

Expand DownExpand Up@@ -40,7 +40,7 @@ Full metadata (commands, remotes, evidence strategy): `~/.config/case/projects.j

## Task Dispatch

Tasks are markdown files that agents execute. Runtime task files live in the target repo's ignored `.case/tasks/active/`.
Tasks are `td` issues that agents execute. Each task is a `td` issue in the target repo's `.todos/` store, identified by a `td-…` issue handle.

- **Format spec**: `tasks/README.md`
- **Templates**: `tasks/templates/`
Expand All@@ -49,11 +49,11 @@ Pipeline: scout → implementer → verifier → reviewer → closer → (retros

Onboarding agent (out of the pipeline): `interviewer` — invoked by `ca onboard --interview` to capture evidence strategy rationale, verification notes, and repo learnings.

Lifecycle: `.case/tasks/active/` → PR opened/merged status in the task JSON
Lifecycle: `td` issue created → PR opened/merged status tracked on the task record

## Working in a Target Repo

0. Run `ca session {repo-path} --task {task-json}` to gather context
0. Run `ca session {repo-path} --task {td-id}` to gather context
1. Read the repo's `CLAUDE.md` (or `CLAUDE.local.md`) for project-specific instructions
2. Run `ca bootstrap {repo-name}` to verify readiness
3. Follow the repo's PR checklist before opening a PR
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,14 +50,14 @@ AGENTS.md # Entry point for agents (routing map)
CLAUDE.md # This file (meta-instructions for case itself)
projects.schema.json # JSON Schema for the project manifest
docs/
architecture/ # Canonical patterns per repo type
architecture/ # Canonical patterns per repo type (+ pipeline.md for case itself)
conventions/ # Shared rules (commits, testing, PRs)
failure-matrix.md # Phase × outcome → action lookup (synced with code)
golden-principles.md # Invariants enforced across all repos
playbooks/ # Step-by-step guides for recurring operations
tasks/
active/ # Current task files for agent execution
templates/# Reusable task templates
templates/ # Spec scaffolds (a filled template becomes a td issue)
# Live task state is a td issue in the target repo's .todos/, not a file here
src/commands/
check.ts # Cross-repo convention enforcement
bootstrap.ts # Per-repo readiness verification
Expand Down
419 changes: 419 additions & 0 deletions MIGRATE_IMPLEMENTATION.md

Large diffs are not rendered by default.

29 changes: 13 additions & 16 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,10 +43,10 @@ ca --agent 1234

`ca --agent` starts an interactive orchestrator session. It can inspect context, fetch issues, help shape the task, create the task file, and then run the pipeline. It should not implement directly. This is the primary interface for “humans steer.”

For an existing task file:
For an existing td task, pass its issue handle:

```bash
ca run --task .case/tasks/active/cli-1-issue-53.task.json
ca run --task td-a1b2c3 --repo-path ../cli/main
```

To resume an interrupted issue run, re-run the same command:
Expand DownExpand Up@@ -109,15 +109,15 @@ ca --agent 1234 # steering session with issue context
ca onboard <path> # add a repo to projects.json
ca onboard <path> --interview # add a repo with an interactive interview
ca onboard <repo> --re-interview # re-interview an already-onboarded repo
ca run --task <file> # run an existing task JSON
ca run --task <td-id> # run an existing td task by its issue handle
ca watch <task-slug> # live-tail the event log
```

Agent-facing commands:

```bash
ca session <repo-path> --task <task.json>
ca status <task.json> [field value...]
ca session <repo-path> --task <td-id>
ca status <td-id> [field value...]
ca mark-tested
ca mark-manual-tested
ca mark-reviewed --critical 0
Expand All@@ -134,8 +134,8 @@ Common flags:

```bash
ca --model claude-opus-4-5 1234
ca run --task <file> --mode unattended
ca run --task <file> --dry-run
ca run --task <td-id> --mode unattended
ca run --task <td-id> --dry-run
ca run --fresh 1234
```

Expand All@@ -150,18 +150,15 @@ Package-level config lives under `~/.config/case/`. Per-repo runtime state lives
agent-versions/

<target-repo>/.case/
active
learnings.md
amendments/
run-log.jsonl
tasks/
active/
<task-slug>.md
<task-slug>.task.json
<task-slug>/
events/
plan.json
working-memory.json

<target-repo>/.todos/ # td issue store (SQLite); a task is a td issue, not a .task.json file
```

Override the config/cache directory with:
Expand All@@ -178,7 +175,7 @@ For portable binary installs, keep `projects.json` in `~/.config/case/` via `ca

## Pipeline

The runtime uses a deterministic TypeScript pipeline executor for phase transitions. The LLMs do the work inside each phase; TypeScript decides which phase runs next.
The runtime drives phase transitions with a deterministic [LangGraph](docs/architecture/pipeline.md) `StateGraph`: the LLMs do the work inside each phase, while TypeScript — the graph routers plus the failure matrix — decides which phase runs next. Runs carrying a SQLite checkpointer resume from the last phase after a crash. Each agent spawn is provider-routed — Claude models run on the Claude Agent SDK, everything else on LangChain (override with `CASE_AGENT_RUNTIME`). See [docs/architecture/pipeline.md](docs/architecture/pipeline.md) for the full picture.

Profiles:

Expand DownExpand Up@@ -241,7 +238,7 @@ Configure models in `~/.config/case/config.json`:
{
"$schema": "https://raw.githubusercontent.com/workos/case/main/config.schema.json",
"models": {
"default": { "provider": "anthropic", "model": "claude-sonnet-4-20250514" },
"default": { "provider": "anthropic", "model": "claude-sonnet-4-6" },
"reviewer": { "provider": "google", "model": "gemini-2.5-pro" },
"verifier": null
}
Expand All@@ -251,7 +248,7 @@ Configure models in `~/.config/case/config.json`:
Priority:

```text
--model flag > explicit spawn options > config file > hardcoded default
--model flag > CASE_MODEL_OVERRIDE env > per-agent config > config default > hardcoded default
```

## Repository Map
Expand DownExpand Up@@ -280,7 +277,7 @@ For case itself:

```bash
bun run typecheck
bun test ./src/__tests__/
bun run test
bun run lint
bun run format:check
```
Expand Down
43 changes: 21 additions & 22 deletions agents/closer.md
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
---
name: closer
description: PR creation agent for /case. Drafts thorough PR descriptions from task file and verification evidence. Verifies all evidence gates before PR creation. Never implements or tests.
description: PR creation agent for /case. Drafts thorough PR descriptions from the task and verification evidence. Verifies all evidence gates before PR creation. Never implements or tests.
tools: ['Read', 'Bash', 'Glob', 'Grep']
---

# Closer — PR Creation Agent

Create a pull request with a thorough description based on the task file, progress log, and verification evidence. You are the only agent that runs `gh pr create`. You must verify all evidence gates yourself before attempting to create the PR.
Create a pull request with a thorough description based on the task, progress log, and verification evidence. You are the only agent that runs `gh pr create`. You must verify all evidence gates yourself before attempting to create the PR.

## Input

You receive from the orchestrator:

- **Task file path** — absolute path to the `.md` task file under the target repo's ignored `.case/tasks/active/`
- **Task JSON path** — the `.task.json` companion
- **td issue handle** — the `td-…` id for this task (shown as **td issue** in the Task Context block); pass it to `ca status`/`ca session`
- **Target repo path** — absolute path to the repo
- **Verifier AGENT_RESULT** — structured output from the verifier (screenshot URLs, evidence markers, pass/fail)

Expand All@@ -24,26 +23,26 @@ You receive from the orchestrator:
Run the session command to orient yourself:

```bash
SESSION=$(ca session <target-repo-path> --task <task.json>)
SESSION=$(ca session <target-repo-path> --task <td-id>)
echo "$SESSION"
```

Read the output to understand: current branch, last commits, task status, which agents have run, and what evidence exists. This replaces manual git log / task file discovery.
Read the output to understand: current branch, last commits, task status, which agents have run, and what evidence exists. This replaces manual git log / task discovery.

### 0.5. Record Start

Mark yourself as running with a start timestamp immediately:

```bash
ca status <task.json> agent closer status running
ca status <task.json> agent closer started now
ca status <td-id> agent closer status running
ca status <td-id> agent closer started now
```

### 1. Gather Context

1. Read the task file (`.md`) — full content including progress log entries from all agents
2. Read the task JSON for issue reference, repo, branch
3. Read verification evidence markers (get task slug from `.case/active`, markers are under `.case/<task-slug>/`):
1. Read the task (`td show <td-id>`) — full content including progress log entries from all agents
2. Read the task record for issue reference, repo, branch
3. Read verification evidence markers (the task slug is the taskId — the **Task** id in the Task Context block, or `SLUG=$(ca status <td-id> id)`; markers are under `.case/<task-slug>/`):
- `.case/<task-slug>/tested` — should have `output_hash` field
- `.case/<task-slug>/manual-tested` — should have `evidence` field (if src/ files changed)
- `.case/<task-slug>/reviewed` — should have `critical: 0` (review findings summary)
Expand DownExpand Up@@ -108,12 +107,12 @@ Closes #<number>

Before running `gh pr create`, verify every requirement.

**CRITICAL: Check the task JSON first.** Read the task JSON and confirm the reviewer agent phase shows `"status": "completed"`. If the reviewer never ran, STOP — do not attempt to create the PR. Report the missing reviewer phase in your error output so the orchestrator can dispatch the reviewer.
**CRITICAL: Check the task record first.** Read the task and confirm the reviewer agent phase shows `"status": "completed"`. If the reviewer never ran, STOP — do not attempt to create the PR. Report the missing reviewer phase in your error output so the orchestrator can dispatch the reviewer.

1. **Reviewer ran**: Read the task JSON and confirm `agents.reviewer.status` is `"completed"`
1. **Reviewer ran**: Read the task and confirm `agents.reviewer.status` is `"completed"`

```bash
test "$(ca status <task.json> agent reviewer status)" = "completed"
test "$(ca status <td-id> agent reviewer status)" = "completed"
```

2. **Branch**: Verify not on main/master
Expand All@@ -128,7 +127,7 @@ Before running `gh pr create`, verify every requirement.
3. **Test evidence**: Read `.case/<task-slug>/tested` — must exist with `output_hash` field

```bash
SLUG=$(cat .case/active | tr -d '[:space:]')
SLUG=$(ca status <td-id> id)
test -f ".case/${SLUG}/tested" && grep -q "output_hash:" ".case/${SLUG}/tested"
```

Expand DownExpand Up@@ -168,7 +167,7 @@ The body must contain verification keywords (any of: "verif", "tested", "test pl
If the reviewer produced warnings or info findings (check `.case/<task-slug>/reviewed` for `warnings` and `info` counts), post them as a PR review comment:

```bash
# Read findings from the reviewer's progress log entry in the task file
# Read findings from the reviewer's progress log entry in the task
# Format as a comment
gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews \
--method POST \
Expand All@@ -188,18 +187,18 @@ Only post if there are actual findings to share. Skip this step if the reviewer

### 5. Record

1. **Update task JSON** — set agent phase completed, then transition status and record PR URL:
1. **Update the task** — set agent phase completed, then transition status and record PR URL:

```bash
ca status <task.json> agent closer status completed
ca status <task.json> agent closer completed now
ca status <task.json> status pr-opened
ca status <task.json> prUrl "<PR URL>"
ca status <td-id> agent closer status completed
ca status <td-id> agent closer completed now
ca status <td-id> status pr-opened
ca status <td-id> prUrl "<PR URL>"
```

Extract the PR URL from the `gh pr create` output. A null `prUrl` makes the task record incomplete — this is not optional.

2. **Append to the task file's Progress Log**:
2. **Append to the task's Progress Log**:

```markdown
### Closer — <ISO timestamp>
Expand Down
Loading