framework-core is the skill that other skills assume already exists. It plays two distinct roles in the same package:
- Passive — shared reference library. Workflow skills (
sprint-testing,test-documentation,test-automation,regression-testing,project-discovery) cite files underreferences/instead of duplicating the same briefing template, dispatch patterns and orchestration doctrine inside every skill. Loading a workflow skill therefore implies loading the relevantframework-core/references/*.mdon demand. - Active — bootstrap trigger. When users adopt this boilerplate by downloading skills à la carte (e.g. cloning
.claude/skills/sprint-testing/only), they end up missing the foundation files those skills depend on (AGENTS.md,.agents/project.yaml,scripts/agents-*.ts, etc.). Invoking/framework-core initregenerates that foundation from the templates shipped undertemplates/.
Without framework-core, every other workflow skill would either silently rely on files that don't exist or copy-paste the same boilerplate-foundation paragraphs into its own references/. This skill is the single source of truth for both.
Two roles
| Role | Trigger | Consumers |
|---|---|---|
| Reference library (passive) | Other skills loading on-demand | sprint-testing, test-documentation, test-automation, regression-testing, project-discovery, adapt-framework |
| Bootstrap (active) | /framework-core init, framework bootstrap, setup framework foundation |
End users adopting the boilerplate, or repairing a partial install |
Passive role: nobody invokes framework-core directly to read a reference — they just cite framework-core/references/<file>.md and the AI loads it. Active role: only the user invokes it, and only when foundation files are missing.
Init: write order
Bootstrap writes files in this exact order. Each step is justified by what depends on what:
.agents/project.yaml— template variable source. Skills resolve{{VAR}}against this. Nothing depends on it yet at this point in the install, so write it first..agents/jira-required.yaml— manifest of Jira custom fields ANDwork_types:(issue types + canonical statuses + canonical transitions) the methodology requires. Read byscripts/check-jira-setup.ts,scripts/sync-jira-workflows.ts, andscripts/agents-lint.ts..agents/jira-fields.json— empty stub ({}). Real catalog is written later bybun run jira:sync-fields. Documented intemplates/jira-fields.json.templateso the file exists from minute zero..agents/jira-workflows.json— empty shell with one entry per declaredwork_type(e.g.{"story": {...}, "bug": {...}, "test_case": {...}}withnull/{}placeholders). Real catalog is written later bybun run jira:sync-workflows. Documented intemplates/jira-workflows.json.templateso the file exists from minute zero.scripts/agents-setup.ts+scripts/agents-lint.ts+scripts/sync-jira-fields.ts+scripts/sync-jira-workflows.ts+scripts/check-jira-setup.ts— the five CLIs that operate on the four files above. Source files live astemplates/scripts/*.ts.template(the.templatesuffix keeps them out of this repo'stsconfig/eslintscope, since they aren't live source code here); strip the.templatesuffix when writing to the destinationscripts/directory. Order within this group does not matter.package.json(penultimate) — merged: declareddependenciesandscriptsfromtemplates/package.json.partial.jsonare added to the existingpackage.jsonif one exists; otherwise the partial is the seed for a freshpackage.json. Mandatory step: without this merge, none of the five scripts written in step 5 are invocable viabun run ….AGENTS.md+ symlinkCLAUDE.md → AGENTS.md(last).AGENTS.mdcites every file written in steps 1-6, so it must be written after all of them. TheCLAUDE.md → AGENTS.mdsymlink must be created after the real file exists.
Files MUST NOT be reordered. The dependency chain is real: a user who runs the bootstrap halfway and then types bun run agents:setup would otherwise hit "missing script" errors.
Post-bootstrap order for the user. After init completes, the report should instruct the user to run, in this exact order:
bun run agents:setup— fill.agents/project.yamlinteractively.bun run jira:sync-fields— populate.agents/jira-fields.jsonfrom their Jira workspace.bun run jira:sync-workflows— populate.agents/jira-workflows.jsonfrom their Jira workspace (interactive on first run for canonical slugs that don't auto-resolve to a workflow's real status / transition names).bun run jira:check— validate that BOTH catalogs satisfy the manifest (custom fields +work_types).bun run lint:agents— confirm every project-variable and Jira reference (custom fields, work types, statuses, transitions) resolves.
Init: idempotency
For each file written in steps 1-7:
- If the destination file does not exist → copy the corresponding template, report
WROTE <path>. - If the destination file already exists → do NOT overwrite, report
SKIPPED <path> (already present).
Exception — step 6 (package.json): never overwrite. Read the existing package.json, merge in the dependencies and scripts declared in templates/package.json.partial.json (only adding keys that are not already present; never modifying existing keys), and write back. If package.json does not exist at all, copy the partial verbatim and report WROTE package.json (from partial).
The init action never deletes files, never modifies values in existing files (only adds), and never runs bun install. Surface deps that need to be installed in the report so the user can run bun install themselves.
Init: platform
| Platform | CLAUDE.md strategy |
|---|---|
| Linux / macOS | Symlink: ln -s AGENTS.md CLAUDE.md |
| Windows | Copy: write the same bytes as AGENTS.md to CLAUDE.md, then warn the user: "On Windows we copied AGENTS.md → CLAUDE.md. Keep the two in sync manually, or convert to a symlink with admin rights." |
Detect platform from process.platform. Symlinks on Windows require either admin rights or developer mode; defaulting to copy avoids permission prompts during bootstrap.
References cited by other skills
| File | Cited by | Purpose |
|---|---|---|
references/briefing-template.md |
sprint-testing, test-documentation, test-automation, regression-testing, project-discovery |
The 6-component subagent briefing template, with concrete filled examples per dispatch pattern. |
references/dispatch-patterns.md |
All workflow skills with a "Subagent Dispatch Strategy" section | Decision table + heuristic for picking Single / Sequential / Parallel / Background. |
references/orchestration-doctrine.md |
Subagents that need orchestration rules without pulling the whole AGENTS.md |
Cacheable mirror of AGENTS.md §"Orchestration Mode (Subagent Strategy)". |
When a skill cites one of these, it includes a Dependencies block at the top (see next section) so the AI knows to load framework-core before continuing.
Dependency declaration for downstream skills
Every workflow skill that cites framework-core/references/*.md should declare it explicitly so the AI knows what to load on demand. Example block to add near the top of the skill's SKILL.md:
## Dependencies
Requires `framework-core`. Loads on demand:
- framework-core/references/briefing-template.md
- framework-core/references/dispatch-patterns.md
The block is documentation — the AI reads it and pulls the cited files. There is no automated wiring: skills are markdown, not code.
Source of truth contract
templates/AGENTS.md.template is a byte-equivalent mirror of the live AGENTS.md at the repo root. Any change to a structural section in one MUST be applied to the other in the same commit. Structural sections include:
- Critical Rules
- Project Variables
- Tool Resolution
- Orchestration Mode
- Skills Available
- Commands Available
- Fundamental Rules
- Git Workflow
- Context System
- MCPs Available
- AI Behavior
- Local Context (PBI)
- CLI Tools
- Test Project Structure
- Quick Reference
Project-specific FACTS (Project Identity table, Environment URLs, Discovery Progress, etc.) are NOT mirrored. Those are populated per-project by /refresh-ai-memory and live only in the live AGENTS.md. The template keeps them as [PLACEHOLDER] rows so a fresh bootstrap surfaces them as TODOs.
This contract is enforced by convention, not tooling — a future linter could diff the two files but is out of scope here.
The same contract applies to templates/project.yaml.template, templates/jira-required.yaml.template, and the five script templates (agents-setup.ts.template, agents-lint.ts.template, sync-jira-fields.ts.template, sync-jira-workflows.ts.template, check-jira-setup.ts.template): they are byte-equivalent mirrors of their live counterparts at the repo root. When the live file evolves, update the template in the same commit.
Note on
jira-fields.json.templateandjira-workflows.json.template: both are shipped as empty stubs (jira-fields.json.templateis{};jira-workflows.json.templateis a shell with one entry per declaredwork_typeandnull/{}placeholders). The real catalogs are generated by runningbun run jira:sync-fieldsandbun run jira:sync-workflowsagainst the user's Jira workspace AFTER bootstrap completes. The bootstrap report should mention these follow-up steps.
Out of scope
framework-core does not:
- Create or modify
.context/files (that belongs to/project-discovery). - Generate or scaffold tests, fixtures, or KATA components (that belongs to
/adapt-frameworkand/test-automation). - Adapt the framework to a specific stack (that belongs to
/adapt-framework). - Refresh project-specific facts in
AGENTS.md(that belongs to/refresh-ai-memory). - Sync OpenAPI / API schemas (that's
bun run api:sync). - Run any external command beyond file writes — no
bun install, nogit, nogh.
If a user invokes /framework-core init and then asks "now configure the project", route them to /project-discovery. If they ask "now wire the test fixtures", route them to /adapt-framework.