Repository navigation
feat(genesis): skill extraction and read-only investigation - #192
Merged
Merged
Conversation
…sing loops SkillExtractor (--extract-skills): At the root episode boundary, distil an accepted contribution into a .agents/skills/ file that the rest of the run inherits. The reference role fires after a PR merges; on this engine a post-merge version is one no later episode of the same run ever sees, so the literal trigger produces a write half that nobody inherits. Running inside the episode puts the skill in the proposal the next episode branches from. Also carries skill bodies in the brief (LocalWorld.skill_bodies), because the reference puts names and relies on skill_read, and this port has no read tools. Without the bodies "read one before using it" is an instruction none of the agents can follow and the loop is decorative. Investigator (--investigate): A manager may mark a delegation read-only (Delegation.readonly). Instead of the recursion the delegation runs an Investigator that reads the node files and records what it finds under ## Findings in that node CONTEXT.md, which enters the version. The fan-out to subagent_investigator is deliberately not ported — that is what a manager with read tools of its own is for, and giving the manager read tools is the session work. Both off by default (skills=None, investigator=None), zero behaviour change. 36 new offline tests. Full suite exit 0.
Birfy
approved these changes
Sep 24, 2026
Birfy
left a comment
Owner
There was a problem hiding this comment.
Reviewed the skill extraction and investigator flow, scope checks, documentation, and tests. The new behavior is opt-in; all 36 focused tests pass locally and CI passes on Python 3.9/3.11/3.12. Approved for merge.
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.
Genesis: skill extraction and read-only investigation -- the loops that were missing
The problem
The port's own docs name both gaps.
"Skills are inherited but never extracted" (
docs/algo-genesis.md). The read half existed:LocalWorld.skills()collects.agents/skills/along the node chain (hierarchical_skill_names/2), and the brief lists the names. The write half did not; no accepted contribution ever produced a skill file, and the domain shipped one hand-written skill so the inheritance path would be "live rather than decorative" -- which it was not, because this port's agents have noskill_readtool, and a name line telling them to "read one before using it" is an instruction none of them can follow.The other gap is not about the paper.
_MANAGER_PROMPTcarries the CONTEXT.md chain and a listing of the files at a node, never their contents -- this port's agents have no read tool. A manager that must decide from the code decides blind, and there was no mechanism to read a node and leave a note about it.Both gaps share a root cause: one proposal is one completion, not a session. An agent reads nothing the brief does not contain.
What this PR adds
Both features are new modules with no imported engine changes.
--extract-skills:SkillExtractor(examples/genesis/_skills.py)The reference
skill_extractorrole (agents/skill_extractor.ex) runs after the PR merges. On this engine a post-merge version is one no later episode of the same run ever sees, so a literal trigger produces the write half and the loop is still open. The port's adaptation runs extraction at the root episode boundary, on the contribution the episode just accepted, so the skill rides in the same proposal and the next agent inherits it -- the loop closes inside one run.The other adaptation is the reason the loop was never actually live:
LocalWorld.skill_bodiesrenders inherited skill bodies into the brief alongside the names, bounded per-file. Without this the feature is decorative -- the reference puts names in the brief and fetches a body withskill_read, this port's agents have no such tool, and "read one before using it" is an instruction none of them follow.Skills are bounded separately from work (
max_skill_edits=2besidemax_edits=4, against the strategy'smax_files_per_diff=6): a lesson trimmed to make room for the file it distilled is self-defeating. The frontmatter (name,description,parameters) is rendered here, not emitted by the model -- the format is the tool's. Counters distinguish the four outcomes that look identical in the artifact: written, duplicate, refused, unparsed.22 tests in
tests/test_genesis_skills.py.--investigate:Investigator(examples/genesis/_investigator.py)A manager marks a delegation
"investigate": true; the delegation runsInvestigator(agents/investigator.ex's read-only half) instead of the recursion, and what it reads at the node is recorded under## Findingsin that node'sCONTEXT.mdand enters the version. The next agent's brief carries the updated record.The fan-out to
subagent_investigatoris deliberately not ported -- that is what a manager with read tools of its own does, and giving the manager read tools is the session work. The one write an investigator may make is the record at the node it was sent to; source edits and writes to an ancestor's record are refused and counted. A read-only delegation with no investigator installed falls through to ordinary work rather than being dropped silently.14 tests in
tests/test_genesis_investigator.py.Backward compatibility
skills=Noneandinvestigator=NoneonRecursiveDelegationare unchanged and default.Delegation(path, objective)signature is unchanged (readonly=False).llm_managerparses"investigate": truewhen present; a reply that omits it works as before.situatewithskill_bodies=False(the default) renders only names, as before.--modeland print an error and exit without one.Verification
Files
10 files changed, +1307, -30
New:
examples/genesis/_skills.py(+295) --SkillExtractor, prompt, dedup, frontmatter renderingexamples/genesis/_investigator.py(+187) --Investigator, prompt, findings persistencetests/test_genesis_skills.py(+316) -- 22 offline deterministic teststests/test_genesis_investigator.py(+205) -- 14 offline deterministic testsModified:
examples/genesis/_delegation.py(+142, -8) --Delegation.readonly,skills=/investigator=fields,_distil,_investigate,_boundskill bucket, countersexamples/genesis/_world.py(+28, -7) --LocalWorld.skill_bodiesfield, body rendering insituate, delegation propagationexamples/genesis/_suite.py(+8, -2) --llm_managerparses"investigate": true; prompt ruleexamples/genesis/genesis_recursive_worlds.py(+47, -2) ----extract-skills,--investigateflags, wiring, summary linesdocs/algo-genesis.md(+32, -11) -- skill-extraction bullet replaces "never extracted"; investigator capability under "two roles"CHANGELOG.md(+47)