feat(manifestos): worker brief injection (#132)#142
Merged
Conversation
Wire the quality + testing manifestos into the worker SDK system prompt
so every dispatched worker reads the project's house rules BEFORE it
sees the issue body. Previously, workers wrote PRs that violated rules
(missing tests, no incremental commits, ignored exit checklist) because
QUALITY.md/TESTING.md were not in-context at generation time.
What
----
- New `forge_loop.manifestos` module:
* `load_manifestos(repo)` — discovery from `<repo>/.forge/*.md`.
Whitespace-only files treated as missing. Unreadable / non-utf8
files swallowed (corrupt manifesto MUST NOT crash worker).
* `render_manifesto_block(bundle)` — formats the MANIFESTO prefix
with `QUALITY RULES YOU MUST FOLLOW:` and `TESTING RULES YOU MUST
FOLLOW:` subsections, quality first. Both missing → empty string
(back-compat: byte-identical pre-feature prompt).
* `inject_into_brief(brief, bundle)` — prepends the block ahead of
any task-specific content.
* Git-blob-style sha1 of each rendered file recorded for telemetry
audit (parity-tested against `git hash-object`).
- `worker.make_brief` gains `manifesto_bundle=` kwarg and prepends
the block when present. `WorkerOutcome` gains a `manifesto_sha`
field (`{"quality": <sha>, "testing": <sha>}` or `None` per side).
- `run_worker` discovers the bundle once per dispatch from the repo
checkout, threads it into both the brief renderer AND the outcome
telemetry payload. Also wired through the iteration-loop
`brief_override` path so round 2 sees the same rules.
Why
---
House rules drift the moment they aren't in-context. Injecting them
at the top of the system prompt frames every subsequent decision the
worker makes — including the exit-checklist + commit-discipline rules
that previously caused mid-session quits with uncommitted work.
Tests (tests/test_worker_manifesto_injection.py)
- Discovery: empty repo, both present, whitespace-only, binary garbage.
- Rendering: both, only-quality, only-testing, whitespace-as-missing.
- Injection: block precedes task-marker; empty bundle is a no-op.
- Telemetry: sha pairs round-trip on outcome for both/partial/none.
- Adversarial: corrupt manifesto → worker still dispatches, null sha.
- Sha parity: implementation matches `git hash-object` byte-for-byte.
Out of scope (per spec)
- Critic prompt injection (separate follow-up).
- Per-ticket manifesto overrides / templating in manifesto bodies.
- Dashboard surfacing of manifesto sha.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owner
Author
|
Source issue #132 was closed mid-flight (state: closed). Loop refusing auto-merge. Reopen the issue OR merge manually. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Inject the active quality + testing manifestos into the worker SDK system prompt so every dispatched worker reads house rules BEFORE seeing the issue body. Closes #132.
forge_loop.manifestosmodule: discovery, rendering, sha-tagging.worker.make_briefprepends aMANIFESTOblock (quality first, then testing) when present.WorkerOutcomegainsmanifesto_sha({"quality": <sha>, "testing": <sha>}per side,Nonewhen absent).run_workerand threads into both brief + outcome (including the iteration-loopbrief_overridepath).Acceptance criteria → how it's tested
test_renders_both_manifestos_when_present,test_manifesto_block_precedes_task_brief.test_silent_skip_when_both_missing.test_partial_render_only_quality,test_partial_render_only_testing.test_whitespace_only_manifesto_treated_as_missing,test_whitespace_only_manifesto_not_rendered_as_empty_header.manifesto_shaon outcome —test_manifesto_sha_in_telemetry_both_present,test_manifesto_sha_null_when_repo_has_no_manifestos,test_manifesto_sha_partial_when_only_one_side_present.test_manifesto_block_precedes_task_brief.test_corrupt_manifesto_does_not_crash_loader,test_corrupt_manifesto_does_not_crash_worker.git hash-object—test_sha_matches_git_hash_object.Test plan
pytest tests/test_worker_manifesto_injection.py— 16/16 passpytest tests/test_manifestos_discovery.py— sibling discovery tests still passruff checkclean on new filesOut of scope (per spec)
manifesto_sha.