feat(launchpad): create the corpus-author agent skill (#629) - #1562
Conversation
.claude/skills/corpus-author/SKILL.md: refuses to draft a second canonical document into a task that already has one; gathers evidence via evidence.py before drafting and checks bundle.conflicts before writing any claim; records the repository revision; resolves the assigned template as merged / open-PR-only / absent and, for "absent", follows AGENTS.md's own already-published fallback (write against node.schema.json, expect a later reshape) instead of inventing one. Scaffolds via scaffold.py, ties FACT eligibility directly to evidence.py's structural fact_eligible flag so pr_review/pr_comment/issue_discussion can never become FACT, and requires a clean validate.py run before proposing completion. Files a second discovered concept as its own task rather than folding it in, per AGENTS.md. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
tucktuck101
left a comment
There was a problem hiding this comment.
Review — corpus-author agent skill (#629)
Step 4 — resolve the template as real, provisional, or absent, and say which — is the PR's
headline contribution and it is genuinely good. The problem is that step 5 makes step 4's most
important branch unreachable.
Blocking — step 5 routes unconditionally through tooling that cannot succeed today
Step 4's "Absent altogether" branch tells the agent to hand-author against
node.schema.json, correctly quoting AGENTS.md. Step 5 then says, with no branch:
scaffold.scaffold_node(root, row, node_type=..., origin=..., revision=revision)At this PR's head, neither side of that call exists: launchpad/docs/corpus/templates/ is
absent, and launchpad/project-intelligence/corpus/scaffold.py is absent too — it arrives with
#1559, which is not merged. Even once scaffold.py lands, _known_templates(root) returns an
empty frozenset while templates/ is missing, so scaffold_node raises ScaffoldError on
every call — and SKILL.md:75-78 tells the agent to accept ScaffoldError as ground truth
rather than proceed.
So an agent that follows steps 1-4 correctly hits a hard stop with no instruction, and cannot
reach step 8's required clean validator run. Step 5 must branch the way step 4 already does:
scaffold when the template is known, otherwise hand-author the frontmatter against
node.schema.json and say so in the node body.
This is also a merge-order matter — the 26 template PRs (#1527-#1556) and #1559 are what make
the scaffold path viable — but the skill should be followable at the revision it merges, and the
branch it needs is one it already describes.
High — node_type and origin are left as literal ellipses with no derivation rule
SKILL.md:80-83 passes node_type=... and origin=.... Both are closed enums that
scaffold_node fails closed on (13 and 4 values, per node.schema.json), and neither is
carried by the manifest row — ManifestRow has template but no type or origin. Step 1
forbids inventing purpose or audiences, yet step 5 forces the agent to invent two schema enum
values that nothing upstream produces. Either derive them from template with a stated mapping,
or add them to the manifest.
Medium — step 1 sources its inputs from a ledger that does not contain them
Step 1 requires path, template, purpose, audiences, source_start_points "from
corpus-plan's ledger", and stops if it cannot get them. corpus-plan defines its ledger as only
the alias-to-issue-number dict (.claude/skills/corpus-plan/SKILL.md:108-110) and declines to
give it a location. None of those fields is in it, so the pipeline stalls at its first handoff.
The data does reach GitHub: plan_from_manifest writes ### Objective, ### Template,
### Audiences and ### Source start points into the issue body (issue_plan.py:60-71).
Point step 1 at the issue body.
What is correct
- The three-way template resolution (merged / open-PR-provisional / absent) with a requirement
to name the PR number when using unmerged content is a genuinely good rule and the right
answer to the state this corpus is actually in. - Recording
git rev-parse HEADas the provenance FACT before drafting matches AGENTS.md. - Treating
_known_templatesas ground truth over the agent's belief about an open PR is
exactly the right instinct. - Frontmatter matches sibling skills.
- CI green at head (latest run per check).
Reviewed by tucktuck101's review lane. The absence of templates/ and scaffold.py at this
head, and the enum requirements, were checked directly.
tucktuck101
left a comment
There was a problem hiding this comment.
Review — corpus-author agent skill (#629)
Step 4 — resolve the template as real, provisional, or absent, and say which — is the PR's
headline contribution and it is genuinely good. The problem is that step 5 makes step 4's most
important branch unreachable.
Blocking — step 5 routes unconditionally through tooling that cannot succeed today
Step 4's "Absent altogether" branch tells the agent to hand-author against
node.schema.json, correctly quoting AGENTS.md. Step 5 then says, with no branch:
scaffold.scaffold_node(root, row, node_type=..., origin=..., revision=revision)At this PR's head, neither side of that call exists: launchpad/docs/corpus/templates/ is
absent, and launchpad/project-intelligence/corpus/scaffold.py is absent too — it arrives with
#1559, which is not merged. Even once scaffold.py lands, _known_templates(root) returns an
empty frozenset while templates/ is missing, so scaffold_node raises ScaffoldError on
every call — and SKILL.md:75-78 tells the agent to accept ScaffoldError as ground truth
rather than proceed.
So an agent that follows steps 1-4 correctly hits a hard stop with no instruction, and cannot
reach step 8's required clean validator run. Step 5 must branch the way step 4 already does:
scaffold when the template is known, otherwise hand-author the frontmatter against
node.schema.json and say so in the node body.
This is also a merge-order matter — the 26 template PRs (#1527-#1556) and #1559 are what make
the scaffold path viable — but the skill should be followable at the revision it merges, and the
branch it needs is one it already describes.
High — node_type and origin are left as literal ellipses with no derivation rule
SKILL.md:80-83 passes node_type=... and origin=.... Both are closed enums that
scaffold_node fails closed on (13 and 4 values, per node.schema.json), and neither is
carried by the manifest row — ManifestRow has template but no type or origin. Step 1
forbids inventing purpose or audiences, yet step 5 forces the agent to invent two schema enum
values that nothing upstream produces. Either derive them from template with a stated mapping,
or add them to the manifest.
Medium — step 1 sources its inputs from a ledger that does not contain them
Step 1 requires path, template, purpose, audiences, source_start_points "from
corpus-plan's ledger", and stops if it cannot get them. corpus-plan defines its ledger as only
the alias-to-issue-number dict (.claude/skills/corpus-plan/SKILL.md:108-110) and declines to
give it a location. None of those fields is in it, so the pipeline stalls at its first handoff.
The data does reach GitHub: plan_from_manifest writes ### Objective, ### Template,
### Audiences and ### Source start points into the issue body (issue_plan.py:60-71).
Point step 1 at the issue body.
What is correct
- The three-way template resolution (merged / open-PR-provisional / absent) with a requirement
to name the PR number when using unmerged content is a genuinely good rule and the right
answer to the state this corpus is actually in. - Recording
git rev-parse HEADas the provenance FACT before drafting matches AGENTS.md. - Treating
_known_templatesas ground truth over the agent's belief about an open PR is
exactly the right instinct. - Frontmatter matches sibling skills.
- CI green at head (latest run per check).
Reviewed by tucktuck101's review lane. The absence of templates/ and scaffold.py at this
head, and the enum requirements, were checked directly.
Duplicate of the identical review posted 6 seconds later by the same lane (a retry after a client-side timeout). Dismissing this copy only; the substantive review still stands below.
…lution Blocking finding from tucktuck101's review confirmed and fixed: step 5 called scaffold.scaffold_node(...) unconditionally, with no branch. Verified against this PR's own head: neither launchpad/docs/corpus/templates/ nor launchpad/project-intelligence/corpus/scaffold.py exists yet, on this branch or on launchpad -- scaffold.py arrives with #1559, unmerged. Once it does land, _known_templates(root) returns an empty frozenset while templates/ is missing, so scaffold_node raises ScaffoldError on every call, and step 8 already tells the agent to treat ScaffoldError as ground truth to stop on. So an agent following steps 1-4 correctly hit a hard stop with no instruction for step 4's "Absent altogether" branch -- the skill's own headline contribution to resolving the template state this corpus is actually in. Step 5 now branches exactly the way step 4 already does: scaffold when the template is merged or provisional, otherwise hand-author the frontmatter directly against node.schema.json (writing the same provenance evidence entry scaffold_node would have) and say so in the node's scope section, per AGENTS.md step 8. Not fixed here (High/Medium, not blocking, reported separately): the node_type/origin literal ellipses with no derivation rule, and step 1's "corpus-plan's ledger" not actually containing the fields it asks for. No automated suite covers SKILL.md prose; verification stamp touched per the hook's documented no-suite fallback, not earned by a test run. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Summary
Adds
.claude/skills/corpus-author/SKILL.md: gathers evidence viaevidence.pybefore drafting, scaffolds viascaffold.py, ties FACTeligibility to
evidence.py's structuralfact_eligibleflag, and resolvesthe "no templates merged yet" gap using
AGENTS.md's own already-publishedfallback instead of inventing one.
Related issue
Closes #629
Issue type
Task
Agent provenance
Objective
.claude/skills/corpus-author/SKILL.md, the corpus-author agent skill issue #629 asks for.Impacted components
.claude/skills/corpus-author/SKILL.md
Note on this diff's base: built directly on
origin/launchpad, samereasoning as #628's PR -- a skill file references
evidence.py/scaffold.pyby path, it doesn't import them, so it doesn't need those PRs merged first
to be a valid artifact.
Approach and rejected alternatives
The templates-gap handling (step 4) is the part of this PR most worth
explaining. When this Feature's tooling steps (#624-#627) were built, zero
corpus templates were merged onto
origin/launchpad-- the plan(
launchpad/plans/2026-08-27-issue-606-corpus-tooling.md) flagged thisexplicitly as an open question rather than deciding it. Rather than resolve
it by inventing a policy, I read
launchpad/docs/corpus/AGENTS.mdforwhether it already had an answer, and it does, verbatim: "Until the
standards land there is no per-type template to follow: write the node
against
node.schema.jsonand the rules above, and expect a later task toreshape it." Step 4 implements exactly that three-way branch (merged / open
PR only / absent), citing
AGENTS.md's own words for the third case insteadof asserting a new rule.
The other substantive design choice: tying
entry_class: FACTeligibilitydirectly to
evidence.py'sfact_eligiblefield (step 6), rather thanre-describing FACT/INFERENCE/TEAM_KNOWLEDGE from scratch.
evidence.py(#625) already makes
pr_review/pr_comment/issue_discussionentriesstructurally incapable of being constructed as fact-eligible -- this skill's
job is to make sure that structural guarantee actually reaches the node's
front matter, not to re-derive the judgment by eye each time.
Rejected: letting the skill invent template content when none is merged.
Rejected because that would be exactly the "invent missing project
decisions" failure this whole Feature's plan and multiple corpus batches
have repeatedly flagged as the recurring risk --
AGENTS.md's documentedfallback exists precisely so nobody has to.
Rejected: skipping the "second concept discovered" section as redundant
with
AGENTS.md. Kept it, briefly, because the corpus batch history (seeproject memory on PRD #605) shows this is a recurring real failure mode
worth a skill-level reminder, not just a document buried in
AGENTS.md'sprose.
Verification
No skill-specific validator exists in this repository.
Command run:
Raw output:
Command run:
Raw output:
(The
FAILline is validate.py's own diagnostic output from a deliberatenonexistent-root test case -- the suite's actual result is
OK, 79/79.)Not verified
Never run by an agent against a real document task -- new instruction text,
not new code, with no harness in this repo for dry-running a skill's
instructions. Did not verify the "open PR exists for this template" branch
against a real template PR from issue #605's track (checked that the
gh pr list --searchcommand shape is plausible, not that it returnsexactly what step 4 assumes for every one of the ~20 open template PRs).
Security implications
None new. Documentation-only. It does direct future authoring to open real
source files and GitHub content as evidence -- no different in kind from
what
AGENTS.mdalready directs.Escalations
None beyond what's already stated in the plan's OPEN section, which this PR
resolves rather than defers further: whether to build corpus-author against
templates that aren't merged yet. Resolved by following AGENTS.md's own
documented answer, not by a new judgment call in this PR.