Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
219 changes: 59 additions & 160 deletions CLAUDE.md

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions skills/tmb_agent-creator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,15 @@ If the user wants a consultant that writes source code (e.g. `data-pipeline-swe`
> "This agent will write source code. The plugin's swe role already exists for that. Are you sure you want a parallel code-writing consultant? It will need `isolation: worktree` and `Write`/`Edit` tools, which means it bypasses bro's task-spec gating."

If they confirm, add `isolation: worktree` to frontmatter and `Write, Edit` to tools. Otherwise, propose a skill instead (use `tmb_skill-creator`) so the existing swe gains the new behavior.

## Headless mode — HALT, do not auto-approve

This skill writes new files into `.claude/agents/`. Per CLAUDE.md doctrine, file-writing skills must NEVER auto-approve in headless mode — the silent generation of agents in CI is exactly the foot-gun the rule guards against.

When `AskUserQuestion` errors OR `TMB_HEADLESS=1` is set:

1. Halt the skill immediately. Do NOT write any files.
2. Record `ledger_log(agent='bro', event_type='headless_creator_blocked', summary='tmb_agent-creator blocked: cannot create agent <proposed_name> without Human approval in headless mode.')`.
3. Surface a clear message: "Cannot create agent in headless mode — file writes require Human approval. Re-run interactively, or write the agent file directly if you know what you want."

Rationale: an agent is a new persona that can be spawned by bro. Silent CI-time generation could ship behavior the Human never reviewed.
9 changes: 9 additions & 0 deletions skills/tmb_branch-id-proposal/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,12 @@ AskUserQuestion({
```

5. Load `tmb_planning-simple` (if triage=simple) or `tmb_planning-difficult` (if triage=difficult) and proceed with planning. The `issue_id` and confirmed `branch_id` carry forward into `task_create_batch` when the spec is ready.

## Headless fallback

When `AskUserQuestion` errors OR `TMB_HEADLESS=1` is set, accept the proposed branch_id without Human confirmation. Per CLAUDE.md doctrine, record both:

- `ledger_log(agent='bro', event_type='headless_fallback', summary='tmb_branch-id-proposal: confirm "<proposed_id>" → auto-accepted')`
- `discussion_append(agent='bro', kind='note', body='Headless fallback: branch-id-proposal asked to confirm <proposed_id>, no Human in loop, auto-accepted. Reason: bro already chose intelligently from project context.')`

Then proceed with the planning chain as if the Human had typed "Yes, proceed". Do NOT auto-pick "Upgrade to difficult" or "Suggest different branch_id" — those require Human intent.
51 changes: 51 additions & 0 deletions skills/tmb_direct-mode/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: tmb_direct-mode
description: Narrow bypass for trivial single-file changes (≤3 lines, no API change, no docs/trustmybot/architecture/ touch) — bro edits the file directly, commits with chore message, logs direct_mode_used to ledger. Skips the planner-spawn-review chain. Loaded when bro recognizes a Direct Mode candidate.
agent: bro
allowed-tools: Read, Edit, Bash, mcp__plugin_tmb_trajectory-server__ledger_log
---

# direct-mode

## Purpose

The default decision chain (Human → bro → SWE → bro task gate → push gate) is correct overkill for a typo fix. Direct Mode is the one-line escape valve: bro edits the file, commits, logs, done. No issue, no task, no SWE spawn, no planning skill.

The narrow scope IS the discipline. If you find yourself extending Direct Mode "just for this one case," stop — that's the slippery slope this rule guards against.

## When to engage — ALL must hold

- **Single file change.**
- **≤3 lines diff.** Typo fix, comment, constant bump, one-line README rewording.
- **No public API change**, no new file, no test change required.
- **No `docs/trustmybot/architecture/` touched** — that's always difficult-triage.

If any condition fails, **fall back to the default chain** — propose an issue + task + SWE spawn with a brief explanation to the Human.

## Protocol

```
Edit (file)
→ Bash (git commit -m "chore: ...")
→ ledger_log(agent='bro', event_type='direct_mode_used', summary='<one-line description of the fix>')
```

That's the whole skill. No `task_create_batch`. No `Task(subagent_type='swe', ...)`. No `planning_complete` ledger event. No bro verification step (the diff is small enough that bro reading it IS the verification).

## Examples

- "@bro fix the typo `recieve` → `receive` in README.md" → Direct Mode
- "@bro bump the timeout constant from 30 to 60 in config.ts" → Direct Mode
- "@bro add a comment explaining why we use BTreeMap here" → Direct Mode

## Counter-examples — NOT Direct Mode

- "@bro rename this function" — touches every caller, multi-file
- "@bro add error handling" — likely test changes too
- "@bro update the README to reflect v0.5" — usually multi-section, plus might touch architecture docs

## Never

- Silently extend Direct Mode to "small but multi-file" — that's a planning skill ask.
- Skip the `direct_mode_used` ledger event. It's how `git log` and the trajectory diverge become reconcilable.
- Use Direct Mode when the change touches anything in `docs/trustmybot/architecture/` — those changes are by definition difficult-triage and need an ADR.
13 changes: 13 additions & 0 deletions skills/tmb_first-run-onboarding/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,16 @@ Emit only after the identity + 3 config writes succeeded AND `ledger_list` confi
> Done. Identity + branching model saved. swe + pr-reviewer + default skills are already available from the plugin — no setup needed in your project. Tell me what you want to work on — trust me bro, it works.

Onboarding Mode ends. If a code-touching ask was held, proceed with it now.

## Headless fallback

When `AskUserQuestion` errors (no Human in loop, e.g. `claude -p`) OR `TMB_HEADLESS=1` is set, use these defaults instead and proceed. Per CLAUDE.md doctrine, **every fallback must be recorded** via both `ledger_log(event_type='headless_fallback', ...)` AND `discussion_append(kind='note', ...)`.

| Question | Default | Reason |
|---|---|---|
| Human name (identity) | `"Anonymous"` | Safe placeholder; recoverable via `tmb_reonboard` |
| Branching model | `"github-flow"` | Most common choice; matches the test fixtures |
| PR target | `"main"` | github-flow default |
| Protected branches | `["main"]` | Minimal safe set |

After applying defaults, complete the rest of the skill flow as normal (call `identity_set`, `config_set` for each policy key, then `ledger_log(event_type='tmb_onboarding_complete', summary='Headless onboarding with defaults — re-onboard via tmb_reonboard for production use.')`).
72 changes: 72 additions & 0 deletions skills/tmb_headless-fallback/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
name: tmb_headless-fallback
description: How bro handles AskUserQuestion errors and TMB_HEADLESS=1 mode — use documented per-skill defaults, audit every fallback to ledger + discussion, never silently accept and never halt. Loaded reactively the first time AskUserQuestion errors in a session.
agent: bro
allowed-tools: mcp__plugin_tmb_trajectory-server__ledger_log, mcp__plugin_tmb_trajectory-server__discussion_append
---

# headless-fallback

## Purpose

`AskUserQuestion` is the only tool bro uses to consult the Human directly. In headless contexts (`claude -p`, CI runs, automated agents) there is no Human in the loop — the call returns an error. This skill defines the protocol bro must follow when that happens.

**Bro must never halt on an `AskUserQuestion` error.** A halted bro produces no audit trail and no result; an autonomous bro using a documented default produces both.

## When to apply

Either condition triggers the fallback path:

- The `AskUserQuestion` call itself returns an error (e.g. "tool errored on both attempts")
- The env var `TMB_HEADLESS=1` is set (skip the call entirely, go straight to fallback)

## Protocol

For every `AskUserQuestion` call in any skill:

1. **Look up the documented default** for that question. Every skill that calls `AskUserQuestion` MUST list defaults under its own `## Headless fallback` section. If the calling skill has no documented default for a question, that's a doctrine bug — log it and halt that specific skill (not bro overall).

2. **Record the fallback to the trajectory DB with TWO writes** — both are required:

```
ledger_log(
agent='bro',
event_type='headless_fallback',
summary='<skill_name>: <question_short> → <chosen_default>'
)

discussion_append(
agent='bro',
kind='note',
body='Headless fallback: <skill> asked "<question>", no Human in loop, defaulted to <default>. Reason: <one-line>.'
)
```

3. **Continue the skill's flow** with the default value as if the Human had typed it.

## Why both writes

- `ledger.event_type='headless_fallback'` — searchable evidence trail. `SELECT * FROM ledger WHERE event_type='headless_fallback'` reconstructs every autonomous decision.
- `discussions` entry — human-readable narrative for post-mortem.

A fallback without both writes is a bug. The audit trail is non-negotiable.

## Exception — file-writing skills

`tmb_skill-creator` and `tmb_agent-creator` write new files into the project tree. Auto-approving silent skill/agent generation in CI is the foot-gun this rule guards against. They MUST halt with:

```
ledger_log(
agent='bro',
event_type='headless_creator_blocked',
summary='<creator>: cannot create <name> without Human approval in headless mode.'
)
```

…and a clear surface message: "Cannot create skill/agent in headless mode. Re-run interactively, or write the file directly if you know what you want."

## Never

- Silently fall back without the ledger + discussion writes.
- Halt the whole bro flow on a single `AskUserQuestion` error — only the calling skill halts (creator skills) or proceeds with a default (everything else).
- Use a default for a question that has no documented fallback in the calling skill.
44 changes: 44 additions & 0 deletions skills/tmb_mcp-error-handling/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: tmb_mcp-error-handling
description: How bro handles MCP tool errors (is_error=true, forbidden, validation, constraint failures) — halt the current flow, surface the exact error, never silently proceed. Loaded reactively on the first MCP error in a session.
agent: bro
allowed-tools: mcp__plugin_tmb_trajectory-server__discussion_append
---

# mcp-error-handling

## Purpose

The MCP trajectory server enforces role-based access control via the `requireRoles` middleware in `mcp/trajectory-server/src/middleware/agent-scope.ts`. When bro calls a tool it shouldn't (e.g. `validation_record`, which is pr-reviewer-only), the server returns `{"error": "forbidden"}`. Same for validation failures, constraint violations, and other errors.

**Doctrine isn't just prompt discipline — it's wire-enforced.** When the server rejects a call, it means the doctrine you're following is wrong, not that you should retry blindly or pretend success.

## Protocol

If any MCP tool result has `is_error: true` (or content includes `{"error": ...}`):

1. **Halt the current flow immediately.** Do NOT proceed to subsequent tool calls as if the call succeeded.
2. **Choose one of two paths:**
- **Surface the exact error to the Human verbatim** and ask how to proceed, OR
- **If the error is recoverable AND you know the correct call**, write `discussion_append(kind='note', body='Recovered from MCP error: <error_text>. Retrying with <corrected_call>.')` and retry the corrected call.

## Errors that mean "doctrine is wrong"

Never silently swallow these:

- `forbidden` — bro called a tool scoped to another role. Reconsider whether the action is bro's responsibility.
- `validation` — input didn't match the schema (e.g. malformed branch_id). Fix the input.
- constraint failures — DB integrity violations (foreign key, unique, etc.). Surface to Human.

## Tools bro must NEVER call

These are scoped to other roles by `requireRoles`. Calling them as `agent='bro'` returns `forbidden`:

- `validation_record` — pr-reviewer only. Bro's task-gate verification writes `ledger_log(event_type='bro_verification_pass', ...)` instead.
- Any consultant-decision tool — consultants don't write decisions either, so this is enforced by absence.

## Never

- Silently retry a `forbidden` error with the same call.
- Fabricate a successful result narrative when the call errored.
- Continue a multi-step flow past an error without surface or recovery.
9 changes: 9 additions & 0 deletions skills/tmb_planning-difficult/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,12 @@ If the difficult triage was wrong (e.g. the ask doesn't actually touch architect
discussion_append(kind='note', body='Triage: simple (downgraded from difficult; reason: <why>)')
# Then load tmb_planning-simple skill instead.
```

## Headless fallback

When `AskUserQuestion` errors OR `TMB_HEADLESS=1` is set, proceed with the spec bro has drafted as if the Human had said "proceed as proposed". Record both:

- `ledger_log(agent='bro', event_type='headless_fallback', summary='tmb_planning-difficult: scope confirmation → auto-accepted')`
- `discussion_append(agent='bro', kind='note', body='Headless fallback: planning-difficult sought scope confirmation, no Human in loop, auto-accepted. Reason: spec was drafted from project context; SWE will surface scope drift if it occurs.')`

Then run the full planning chain (architecture probe, ADR draft, batched task_create_batch + spawn swe + ledger_log). Do NOT skip the ADR — that's the difficult-triage's primary deliverable.
45 changes: 45 additions & 0 deletions skills/tmb_push-gate/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
name: tmb_push-gate
description: How bro handles `git push` blocked by the pre-push hook — query unsigned tasks, spawn pr-reviewer in parallel for each, surface pass/fail to Human. The push gate is bro's only pr-reviewer interaction; reviewer never fires per-task. Loaded when Human says "review before push" or hook blocks push.
agent: bro
allowed-tools: Task, Bash, mcp__plugin_tmb_trajectory-server__task_get, mcp__plugin_tmb_trajectory-server__validation_history
---

# push-gate

## Purpose

PR-Reviewer is **the push gate**, not a per-task reviewer. It runs only at `git push` time, over a batch of unsigned tasks, so its cost is amortized. Bro alone gates each individual task at close (via `bro_verification_pass` ledger event); pr-reviewer's deeper review fires only when commits are about to leave the developer's machine.

## When invoked

Two triggers:

1. The pre-push hook (`scripts/hooks/git-push-guard.sh`) blocks a `git push` because one or more commits being pushed correspond to tasks without a `validation_attempts.verdict='pass'` row. The hook's message:

> BLOCKED: pushing N unsigned commits. Run `@bro review before push` to get pr-reviewer sign-off.

2. The Human says `@bro review before push` (or any phrase containing "review before push").

## Protocol

1. **Query MCP** for tasks with `commit_sha NOT NULL` AND no passing `validation_attempts.verdict='pass'` row. These are the unsigned-task batch.
2. **For each task in the batch, spawn `pr-reviewer`** with `task_id=N`. Run them in parallel where possible — they're independent.
- `pr-reviewer` ships globally with the plugin. **No file copy needed.** CC's agent dispatcher discovers it automatically.
3. **Each pr-reviewer signs off** with `validation_record(verdict='pass'|'fail', ...)`.
4. **On all-pass:** tell the Human the push is unblocked. They re-run `git push`.
5. **On any fail:** surface the failure verbatim. The Human chooses:
- Accept the fix scope → bro spawns swe to address.
- Abort the push.

## Why this design

- pr-reviewer is heavy (full diff read + skill loading + verdict authoring). Per-task review would multiply that cost by the task count.
- The push moment is the natural batch boundary — Human is already pausing to ship.
- Bro's task-gate verification (`bro_verification_pass`) is the lighter always-on check; pr-reviewer is the deeper occasional check.

## Never

- Spawn pr-reviewer at task close. That's bro's job (verification + ledger event).
- Spawn pr-reviewer outside the push gate. There's no other moment it should fire.
- Skip a pr-reviewer fail because "the push is urgent". Either accept the fix or abort. Surfacing-and-shipping-anyway corrupts the audit trail.
10 changes: 10 additions & 0 deletions skills/tmb_reonboard/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,13 @@ After writes, `config_list(agent='bro')` + `identity_get(agent='bro')` to confir
| `config_list()` or `identity_get()` fails | Report the exact error, offer to retry or abort. Do NOT proceed with stale state. |
| `config_set` or `identity_set` fails | Report the exact error, retry the same call. Do NOT skip and continue. |
| Invalid answer (e.g. unparseable Other for branching) | Re-ask via a second `AskUserQuestion` round, omit the invalid answer. |

## Headless fallback

When `AskUserQuestion` errors OR `TMB_HEADLESS=1` is set, **do not silently overwrite policy keys with defaults** — re-onboard is by definition a Human-driven re-confirmation. Instead:

1. Halt the skill cleanly.
2. Record `ledger_log(agent='bro', event_type='headless_reonboard_blocked', summary='tmb_reonboard cannot run headless: policy keys (branching_model, pr_target, protected_branches) require explicit Human re-confirmation.')`.
3. Surface a clear message: "Re-onboarding requires interactive input. Re-run with a Human in the loop, or use `config_set` directly if you know the values."

Rationale: re-onboarding flips policy keys that drive `git-guards.sh` and other hooks. A silent fallback here could break the project's git workflow with no audit trace pointing to the cause.
12 changes: 12 additions & 0 deletions skills/tmb_skill-creator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,15 @@ Tell the Human in one line: skill landed at `<path>`; attached to `<agents>`. Re
- **Never overwrite an existing project skill.** Name collision = Human resolves.
- **Approval is non-negotiable.** Write nothing without an explicit Yes.
- **Stay focused.** A skill should encode one cohesive concern (e.g. "python verification checks", not "python rules + js rules + go rules"). Propose splitting if the body grows past ~50 lines.

## Headless mode — HALT, do not auto-approve

This skill writes new files into `.claude/skills/`. Per CLAUDE.md doctrine, file-writing skills must NEVER auto-approve in headless mode — the silent generation of skills in CI is exactly the foot-gun the rule guards against.

When `AskUserQuestion` errors OR `TMB_HEADLESS=1` is set:

1. Halt the skill immediately. Do NOT write any files.
2. Record `ledger_log(agent='bro', event_type='headless_creator_blocked', summary='tmb_skill-creator blocked: cannot create skill <proposed_name> without Human approval in headless mode.')`.
3. Surface a clear message: "Cannot create skill in headless mode — file writes require Human approval. Re-run interactively, or write the skill file directly if you know what you want."

Rationale: a skill is a behavior change to the agent ecosystem. Silent CI-time generation could ship behavior the Human never reviewed.
Loading