Summary
Decouple the cloud agents' reasoning layer from lock recompilation by extracting it into async-updatable skills, so a logic edit no longer forces a .lock.yml rebuild. Two concentrated targets carry nearly all the value: (1) the triplicated sdd-execute-* procedure → one shared skill, and (2) the five hot shared/*.md fragments → an async-loadable skill layer. The compiled frame of each workflow (triggers, permissions, tools, safe-outputs) stays in the lock unchanged.
This is the runtime/execution counterpart to #232, which converges the authoring layer into portable local skills and explicitly leaves cloud execution out of scope. Same single-source-fragment idea; opposite end of the pipeline.
Framing: frame vs reasoning
No agentic workflow can become entirely a skill. Each compiles a frame GitHub Actions needs statically and cannot defer:
on: / workflow_call, roles, permissions
engine, network, observability, secret-masking
tools (MCP/gh-proxy startup)
safe-outputs — expand into separate Actions jobs with their own minted tokens
All 12 engine-bearing agents carry a safe-outputs: block. That layer must remain in .lock.yml.
What can move async is the reasoning layer: the prompt body + imported shared/*.md fragments. Today both are compile-time inlined (inlined-imports: true, pinned @main), so recompile-locks.yml (triggers: shared/**, .github/workflows/*.md) rebuilds the affected 100–256 KB locks on every logic edit.
Current state (measured)
12 agentic workflows (sample excluded as scaffold). Reasoning-layer weight is uneven:
| Workflow |
Body lines |
Imports |
Skill value |
| sdd-execute-opus / sonnet / haiku |
838 ×3 |
10 |
Highest — one 838-line procedure triplicated across 3 locks, differing only by model tier |
| sdd-spec |
1010 |
6 |
High |
| sdd-triage-arch |
497 |
7 |
High |
| sdd-validate |
412 |
4 |
Medium |
| distillery-sync |
326 |
0 |
Medium (self-contained) |
| sdd-triage-materialize / plan |
~290 |
4 |
Medium |
| sdd-dispatch / derive / review |
175–234 |
3–6 |
Low — frame-dominant |
Fragment reuse (the cross-cutting async cost): sdd-interaction.md ×11, repo-conventions.md ×11, principles.md ×10, sdd-proof-artifacts.md ×8, sdd-mcp-serena.md ×7. Editing one of these fans out a recompile of up to 11 locks.
Constraint
gh-aw has no native runtime-skill loader. "Async" must be achieved one of two ways, each with a cost:
- Operator-side
/-skill — the sdd-workflow-skills.md model (babysit / needs-human-triage / merge-train). Fully decoupled (runs in a human's Claude session, outside CI), but only covers supervise/triage/merge, not the agents' own reasoning.
- Runtime-fetched instruction doc — the agent pulls
shared/skills/X.md@main via gh over the firewall (defaults already allows github) at run start instead of inlining. Achieves true async update, but trades away compile-time validation, @sha pinning, and reproducibility — a real auditability cost for a security-sensitive SDD pipeline where lock behavior currently cannot change without a lock diff.
Any runtime-fetch design must preserve the redaction/firewall guarantees and add a fallback (fetch failure ⇒ degrade, never hard-fail a run).
Proposal — two targets
Target A: sdd-execute-* tier collapse → one shared execute skill
The single highest-value conversion. The 838-line procedure is identical across the opus/sonnet/haiku locks; only the model tier differs. Extract the procedure to one source (shared/sdd-execute.md already imports 10 fragments — factor the body itself the same way), so the three wrappers/locks reduce to frame + tier + a single shared reasoning source. Collapses 3× duplication and removes ~750 KB of regenerated lock per procedure edit.
Target B: hot fragments → async-loadable skill layer
Convert the top five reused fragments (sdd-interaction, repo-conventions, principles, sdd-proof-artifacts, sdd-mcp-serena) so a cross-cutting prose edit no longer fans out an 11-lock recompile. Reuse the single-source + drift-snapshot mechanism #232 point 2 proposes rather than inventing a second one.
Scope
- In: reasoning-layer extraction for Target A + B; the fetch-or-inline decision with its reproducibility/redaction analysis; drift-snapshot guard shared with #232.
- Out: any change to the compiled frame (triggers/permissions/tools/safe-outputs); local authoring/execute (owned by #232); the
.github/ protected-path constraint (#220).
Acceptance
Reuse anchors (do not rebuild)
shared/*.md fragment set + imports: composition; inlined-imports / recompile-locks.yml; the drift-snapshot pattern (scripts/test-digest-snapshot.py); sdd-workflow-skills.md operator-skill format; #232 single-source composition step; decisions/ ADR convention.
Summary
Decouple the cloud agents' reasoning layer from lock recompilation by extracting it into async-updatable skills, so a logic edit no longer forces a
.lock.ymlrebuild. Two concentrated targets carry nearly all the value: (1) the triplicatedsdd-execute-*procedure → one shared skill, and (2) the five hotshared/*.mdfragments → an async-loadable skill layer. The compiled frame of each workflow (triggers, permissions, tools, safe-outputs) stays in the lock unchanged.This is the runtime/execution counterpart to #232, which converges the authoring layer into portable local skills and explicitly leaves cloud execution out of scope. Same single-source-fragment idea; opposite end of the pipeline.
Framing: frame vs reasoning
No agentic workflow can become entirely a skill. Each compiles a frame GitHub Actions needs statically and cannot defer:
on:/workflow_call,roles,permissionsengine,network,observability,secret-maskingtools(MCP/gh-proxy startup)safe-outputs— expand into separate Actions jobs with their own minted tokensAll 12 engine-bearing agents carry a
safe-outputs:block. That layer must remain in.lock.yml.What can move async is the reasoning layer: the prompt body + imported
shared/*.mdfragments. Today both are compile-time inlined (inlined-imports: true, pinned@main), sorecompile-locks.yml(triggers:shared/**,.github/workflows/*.md) rebuilds the affected 100–256 KB locks on every logic edit.Current state (measured)
12 agentic workflows (
sampleexcluded as scaffold). Reasoning-layer weight is uneven:Fragment reuse (the cross-cutting async cost):
sdd-interaction.md×11,repo-conventions.md×11,principles.md×10,sdd-proof-artifacts.md×8,sdd-mcp-serena.md×7. Editing one of these fans out a recompile of up to 11 locks.Constraint
gh-aw has no native runtime-skill loader. "Async" must be achieved one of two ways, each with a cost:
/-skill — thesdd-workflow-skills.mdmodel (babysit / needs-human-triage / merge-train). Fully decoupled (runs in a human's Claude session, outside CI), but only covers supervise/triage/merge, not the agents' own reasoning.shared/skills/X.md@mainviaghover the firewall (defaultsalready allows github) at run start instead of inlining. Achieves true async update, but trades away compile-time validation,@shapinning, and reproducibility — a real auditability cost for a security-sensitive SDD pipeline where lock behavior currently cannot change without a lock diff.Any runtime-fetch design must preserve the redaction/firewall guarantees and add a fallback (fetch failure ⇒ degrade, never hard-fail a run).
Proposal — two targets
Target A:
sdd-execute-*tier collapse → one shared execute skillThe single highest-value conversion. The 838-line procedure is identical across the opus/sonnet/haiku locks; only the model tier differs. Extract the procedure to one source (
shared/sdd-execute.mdalready imports 10 fragments — factor the body itself the same way), so the three wrappers/locks reduce to frame + tier + a single shared reasoning source. Collapses 3× duplication and removes ~750 KB of regenerated lock per procedure edit.Target B: hot fragments → async-loadable skill layer
Convert the top five reused fragments (
sdd-interaction,repo-conventions,principles,sdd-proof-artifacts,sdd-mcp-serena) so a cross-cutting prose edit no longer fans out an 11-lock recompile. Reuse the single-source + drift-snapshot mechanism #232 point 2 proposes rather than inventing a second one.Scope
.github/protected-path constraint (#220).Acceptance
sdd-execute-*procedures derive from one source; a drift-snapshot test fails if any diverges.recompile-locksstays green; no compiled frame changes.Reuse anchors (do not rebuild)
shared/*.mdfragment set +imports:composition;inlined-imports/recompile-locks.yml; the drift-snapshot pattern (scripts/test-digest-snapshot.py);sdd-workflow-skills.mdoperator-skill format; #232 single-source composition step;decisions/ADR convention.