Skip to content

Async-updatable skill layer: decouple agent reasoning from lock recompiles (execute-tier collapse + hot fragments) #340

Description

@norrietaylor

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

  • The three sdd-execute-* procedures derive from one source; a drift-snapshot test fails if any diverges.
  • Editing a hot fragment updates agent behavior without a per-workflow lock diff (or, if inline is retained, the recompile fan-out is measured and the async cost/benefit is recorded as an ADR decision).
  • Fetch-or-inline decision recorded as an ADR, with the redaction/firewall/reproducibility tradeoff explicit and a fetch-failure degrade path.
  • recompile-locks stays green; no compiled frame changes.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions