Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(playbook): guarded subagent writes self-inject agent_id

merged#2531CedarCopilot

CedarCopilot wants to merge 0 commits into staging from fix/guarded-subagent-agent-id

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Aug 20, 2026, 1:52 PM
  2. Merged
    Aug 20, 2026, 6:27 PM
  3. Live on prod
    Aug 20, 2026, 6:27 PM
  4. Observed 27 hours
    Aug 20, 2026, 6:27 PM
  5. Pipelines steady after this deploy
    Aug 20, 2026, 6:27 PM
  6. Unobserved

    Live on prod, no production signal yet

    Aug 21, 2026, 9:12 PM

Behaviors Libra is checking

Direct guarded writes of new subagent documents now assign a stable UUID agent_id in both frontmatter and document metadata, allowing referenced cron/subagent playbook entries to pass verification and run.Inconclusivelow confidence

OTEL fallback found no prod spans matching writeResourceGuarded (/subagents/ document writes) since deploy.

prod, checked Aug 21, 2026, 9:12 PM
Guarded writes for subagents that already declare an agent_id preserve their content and mirror that existing ID into metadata.Inconclusivelow confidence

OTEL fallback found no prod spans matching writeResourceGuarded (/subagents/ document writes) since deploy.

prod, checked Aug 21, 2026, 9:12 PM

Libra has verdicts on 0 of 2 tracked behaviors on prod; 2 are still being checked. Libra checks hourly for 3 days after each deploy.

What was wrong

A subagent .md created straight through writeResourceGuarded (the low-level guarded write) persisted with no agent_id whenever the caller hadn't run prepareSubagentWrite first. Everything routed through writeDocumentTool (the chat document-write tool) is fine , it runs the hook. But direct guarded writes (staff/admin scripts, rollout tooling) skip it.

The consequence is a self-inconsistency in the guard: verifyPlaybook requires every cron/subagent <ref> target to carry agent_id in documents.metadata, so a playbook that references a just-written subagent gets rejected by the guard's own verifier:

VERIFY_FAILED: Ref "<id>" in cron trigger has no agent_id in metadata
… Subagent ref "<id>" is missing agent_id , execution will fall back to SHA-256 path

A standing heal-subagent-agent-ids.ts script exists precisely because this drift recurs.

What changed

writeResourceGuarded now runs prepareSubagentWrite(path, content, metadata) at the top, so every guarded subagent write is self-consistent , agent_id is injected into both the frontmatter and documents.metadata.

  • Idempotent: prepareSubagentWrite returns unchanged when an agent_id is already present.
  • Scoped: only /subagents/ paths are touched. Resource files and PLAYBOOK.md are unaffected.
  • Safe on patch/append: there content is a fragment (or undefined), where injection is a no-op and only config metadata is forwarded , no behavior change for existing edits.

One import + a ~13-line guarded call; no new control flow in the branches.

How to test

vitest run apps/server/src/services/playbook/__tests__/guarded-write.test.ts

New cases:

  • creating a brand-new subagent injects a UUID agent_id into the frontmatter and mirrors it into metadata.agent_id (what the verifier reads);
  • idempotency , a subagent that already declares agent_id keeps it.

All 27 pre-existing guarded-write tests still pass (29 total). @zero/server typecheck clean.

🤖 Generated with Claude Code

Greptile Summary

The PR makes guarded subagent writes inject and mirror a stable agent_id, including for callers that bypass the higher-level document tool.

  • Runs subagent preparation at the guarded-write boundary before mode-specific processing.
  • Adds regression coverage for new identifier injection and preservation of an existing identifier.

Confidence Score: 4/5

The PR appears safe to merge after addressing the non-blocking import-convention issue.

The guarded-write behavior is scoped and idempotent for the tested subagent paths, and the only accepted concern is the newly added relative import.

Files Needing Attention: apps/server/src/services/playbook/guarded-write.ts

Important Files Changed

FilenameOverview
apps/server/src/services/playbook/guarded-write.tsAdds centralized subagent identity preparation; behavior is appropriately scoped and idempotent, with one non-blocking import-style violation.
apps/server/src/services/playbook/tests/guarded-write.test.tsAdds focused regression tests covering identifier injection into frontmatter and metadata and preservation of existing identifiers.
Prompt To Fix All With AI
### Issue 1
apps/server/src/services/playbook/guarded-write.ts:25
**Relative hook import added**

The new `prepareSubagentWrite` dependency uses a relative path instead of the repository-required absolute import convention, making this import inconsistent with the project’s prescribed module style.

```suggestion
import { prepareSubagentWrite } from '@/services/playbook/playbook-doc-hooks';
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: ["fix(playbook): guarded subagent writ

Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/services/playbook/__tests__/guarded-write.test.tsno production surface mapped
  • apps/server/src/services/playbook/guarded-write.tsno production surface mapped