Skip to content

Companion (V2)

Companion is the background loop layer of the plugin — five small hook handlers that fire on Claude Code events (PreToolUse, PostToolUse, UserPromptSubmit, Stop) and keep the work Claude does for you honest against the workbook.

Design principle: Companion is silent unless something material happened. If you're mid-implementation and nothing is committed-decision-ish, Companion stays out of your way. When you finish a verify, when you mark a task DONE, when you say "save progress" — those are the moments it speaks up.

The pillars

1. Proactive verify gate

Blocks mcp__dezycro__update_task calls that try to mark a path-linked task as DONE or PUSHED when no recent passing verifier run is on file. The agent receives a structured deny with the specific paths and the exact /dezycro:verify --path <p> command to run.

Why: prevents the most common silent failure — Claude marking work "done" when the verifier would have failed it.

Override: set companion.autoVerify.preTaskDone: false in .dezycro/config.json.

2. Spec-publish nudge

Tracks every Edit / Write / MultiEdit against companion.autoVerify.controllerPaths (default: **/controllers/**, **/api/**). When a controller path is touched, Companion records the change and sets needsSpecPublish=true.

The next /dezycro:verify run reads that flag and chains /dezycro:publish-spec first, so you never run the verifier against a stale spec.

After 5 controller edits without a verify, Companion emits a one-line pulse nudge.

3. Workbook sweep — trigger-based, silent by default

When the agent finishes a turn, Companion does nothing by default. It fires the workbook-sweep directive only when one of these is true:

  • The user said a wrap phrase on this turn: save progress, log what we did, /dezycro:sync, wrap up, we're done, end of session, etc.
  • /dezycro:verify just completed this turn (snapshot moment for committed decisions).

When it does fire, the directive asks the agent to scan the recent conversation for:

  • Decisions (committed technical/product choices)
  • Issues (current blockers/bugs)
  • Assumptions (unverified beliefs)
  • Task-status hints (a tracked task is now DONE/PUSHED)

…with confidence thresholds per the configured preset (default conservative: 0.85 / 0.80 / 0.90 / 0.90). The agent then calls the matching MCP workbook tool (add_decision, add_issue, add_assumption, update_task) and announces what it logged in plain English, with an 'undo that' if wrong suffix.

Caps: at most 2 entries per turn, 10 per session (configurable). Content-hash dedup against a 32-entry ring buffer prevents the same decision from being logged twice.

Undo: type undo that on the next user turn (within the immediate-next-turn window) and Companion emits a reversal directive that flips the entry to INVALIDATED / CANCELLED / restores the prior task status.

4. Coverage nudges

Two nudges, both deterministic — no LLM round-trip:

  • Pre-PUSH: when you mark a task PUSHED and the verifier passed, Companion surfaces a one-liner of remaining coverage gaps via the system-message channel. Never blocks; informational only.
  • Post-verify Stop: if a verify completed after the previous snapshot was last surfaced, Companion emits a coverage delta (e.g. Coverage delta since last verify: -2 paths uncovered, -1 baseline stale).

The one-liner format pluralizes and omits zero-count segments:

Coverage: 3 paths uncovered, 1 endpoint not in spec

5. /dezycro:author sanity check

When the agent calls change_document_status to push a TRD to APPROVED, Companion runs a light deterministic sanity check against the most-recent draft sidecar — flags obvious placeholder tokens (TBD, TODO, FIXME) and warns on tiny drafts so a half-finished doc doesn't accidentally get marked as approved.

There's no schema enforcement — TRDs don't have a required structure. The check exists as a "did you mean to do that?" guard, not as a content gate.

Configuration

All settings live in .dezycro/config.json under the companion key. Defaults (you can override any of these per-repo):

{
  "companion": {
    "safeMode": false,
    "autoVerify": {
      "preTaskDone": true,
      "prePush": true,
      "postEditPulse": { "enabled": true, "threshold": 5 },
      "autoPublishSpecOnControllerChange": true,
      "controllerPaths": ["**/controllers/**", "**/api/**"]
    },
    "autoWorkbookUpdates": {
      "enabled": true,
      "preset": "conservative",
      "maxAutoLogsPerTurn": 2,
      "maxAutoLogsPerSession": 10,
      "thresholds": {
        "decision": null,
        "issue": null,
        "assumption": null,
        "taskStatus": null
      }
    },
    "coverageNudges": {
      "enabled": true,
      "staleBaselineDays": 14
    }
  }
}

Confidence presets

Preset Decision Issue Assumption Task-status
conservative 0.85 0.80 0.90 0.90
balanced 0.75 0.70 0.80 0.85
aggressive 0.60 0.55 0.70 0.75

Numeric thresholds.* overrides win over the preset (per-type).

Kill switch

Set companion.safeMode: true to disable all Companion behaviors except the deterministic Pillar 1/2 gates. Or disable individual pillars via the per-key enabled: false flags.

State and logs

Companion writes two files under .dezycro/:

  • companion-state.json — session counters, ring buffers, last verify timestamp, coverage snapshot. Safe to delete (regenerates).
  • companion.log — JSON-lines log of every hook firing. Tail with tail -f .dezycro/companion.log | jq to debug.

Both files are gitignored by /dezycro:init.

Manual trigger

You can also drive Companion's workbook sweep directly:

/dezycro:sync

Or say "save progress" — the next assistant turn-end will fire the sweep.