Generator design¶
Status: design. stone check, stone check-writing, stone check-evidence, stone spec apply,
and stone render for the roles of all profiles are built (see stone/). The other
commands are not built yet.
Goal¶
Write the files for a target repo from the framework, one harness adapter, one spec-tool adapter, and the repo config. The same inputs MUST give the same files.
| Item | Value |
|---|---|
| Trigger | A person runs the CLI, or the setup skill runs it |
| Inputs | framework/ (this repo, at a version tag), the selected harness adapter and model profile, .cornerstone/config.yaml, profile overrides |
| Outputs | Instruction file, skills, roles, hooks, CI workflows, check scripts, templates, .cornerstone/manifest.yaml |
| Owner | brawblan |
Reason for a CLI plus a skill: a deterministic CLI gives repeatable files, and generated free-text context files did not help agents (dossier A3, A4). The skill only collects facts and fills the repo config.
Parts¶
| Part | Job |
|---|---|
stone CLI (Python 3) |
Read the inputs, validate them, render the templates, write the files and the manifest. |
setup skill |
The entry skill. Run project-setup as the Shape step (constitution and AGENTS.md). Then survey the repo, interview the human for missing facts, write .cornerstone/config.yaml, and run the CLI. project-setup stays usable alone. |
| Templates | Text files with $name placeholders in framework/adapters/<adapter>/templates/ (D12). |
| Component list | framework/adapters/<adapter>/components.yaml: the id, kind, purpose, principle, eval, template, and target path of each component. A component can have when (D24) and ci_step, a step that render adds to the G3 workflow (D28). |
Commands¶
| Command | Does |
|---|---|
stone init |
Make .cornerstone/config.yaml with TODO(<owner>) values. |
stone render |
Write all files from the inputs. Safe to run again. Built in v0.2 for the single-ticket profile: role files, the protected-path hook, K6, the G3 CI workflow, and the manifest. Version 0.4 adds the app-slice profile and the planner role. Version 0.7 adds K14 to the G3 workflow (D23). Version 0.8 derives profile support from the role files of the adapter, and filters components with when (D24). Item 6b adds check K7 to the G3 workflow (D27). K15 and its G3 step render for a profile with K15 (D28). Item 6d adds the steps for the "by profile" checks K4, K5, K8, K10, K11, and K12 (D29). Item 6g adds the trigger workflows (D31). No profile overrides yet. |
stone spec apply <plan> |
Apply the spec delta of one plan, and write the specs (D21). Built in v0.5. |
stone spec sync |
Renumber the applied deltas and write the specs again, after a merge (D22). Built in v0.6. |
stone check |
Validate the config, the profiles, and the manifest. Report drift between files and templates. Built in v0.1. It tests the eval plan and the review date of each component (D43). No drift test yet. |
stone check-writing |
Run K17 on files, on the changed lines since a base, or on a PR body. Built in v0.1. |
stone check-evidence |
Run K14 on a PR body: fail if a required section is missing or empty. Built in v0.5. |
stone check-specialists |
Run K20 on a PR body and the PR labels: fail on a blocking specialist finding or a missing blocking report (D66). Built in v1.2. |
stone review |
List the components past review_by. Exit code 1 if there are any. |
stone eval <component-id> |
Run the component's eval with and without the component (D26). Built in v0.9. |
stone refresh <harness> |
Start the adapter-refresh profile for one harness. Framework repo only. (Later version.) |
Constraints¶
- Python 3.11 or later. Type hints. No network access during
render. - Idempotent: a second
renderwith the same inputs changes no file. - The generator owns a whole file, or a block in a shared file (D13):
- A whole file (a role file, a hook, a check script, a CI workflow) has no markers. The manifest has its hash. A file that does not match that hash is drift.
- A block in a shared file (for example the instruction file) sits between markers. Content outside the markers belongs to the human.
- An entry in a shared JSON file (for example the harness settings) is merged in. The other keys belong to the human. If the human removes the entry, that is drift.
<!-- stone:begin id=instruction.commands hash=<sha256> -->
...generated content...
<!-- stone:end -->
- The framework version is pinned in the repo config (
framework_version). - Secrets: the CLI never reads or writes a secret value. Templates use placeholders such as
[HARNESS_TOKEN]. The adapter names the real secret.
Trigger workflows¶
stone render writes one CI workflow for each trigger of a selected profile that is not command
(D24, D31). The adapter has one template for each trigger type. A trigger type with no template is
skipped, with a log line.
| Trigger | Starts when | The report goes to |
|---|---|---|
label:<name> |
A human adds the label to an issue. The label asks for a readiness check (D41). | A comment on the issue |
schedule:<daily\|weekly\|monthly\|cron> |
The schedule, or a person with write access | A new issue |
ci:issue-opened |
A user opens an issue | A comment on the issue |
ci:dependency-pr |
A dependency bot opens a PR | A comment on the PR |
Each workflow has two jobs:
- The run job starts the first role of the profile. The prompt has the profile steps. The role gets a read-only token, the event text in a file, and no edit, shell, or web tools. It returns a report.
- The post job posts the report. Only this job has a write token, with the minimum permissions.
Rules:
- Event text goes to a step only through
env, never inline in arunscript (dossier F8). - The prompt tells the role that the event text is data, not instructions.
- The prompt has no relative link. Render rewrites each relative Markdown link to its text (D41).
- A
label:workflow of a shaper tells it to report the missing Definition of Ready items. It does not interview a human, because the job has none (D41). - Each job has a time limit, and the role has a turn limit. Anyone can start some triggers, and each run costs model time (D38, dossier F13).
- The post job frames the report. A fixed header says that a model wrote it from untrusted event text. The report goes in a quote, and no mention in it notifies a person (D38, dossier F14).
- If two selected profiles use the same label, each run also needs the label
profile:<id>. - The harness secret is
[HARNESS_TOKEN]in the core. The adapter names the real secret. - Each workflow is one component,
trigger.<type>.<profile>, with its own review date.
Flow of stone render¶
- Load the framework at the pinned version.
- Load and validate the repo config. Stop on the first error. Print the field and the fix.
- Resolve each profile: framework profile, then the repo override. Apply the rules in customization.md. Stop if a waiver removes G3 or G5.
- Resolve the mode for each profile (repo config, then profile override, then profile default).
The ticket mode applies at run time, not at render time. So render the components for each mode
in
modes_allowedin the repo config. The default is all three modes. - Build the component list from the profiles, the modes, the adapters, and
.cornerstone/local/. - Render each component to memory.
- Compare each rendered block with the file on disk:
- Same content: skip.
- No file on disk: write it.
- The disk content has the hash in the manifest: write the new content.
- Otherwise (a human changed the file, or wrote it before the first render): report drift. Do not overwrite. Exit code 2.
- Write the manifest. Keep
added,owner, andreview_byfor existing components. - Print a summary: files written, files skipped, drift found.
Errors and logging¶
| Error | Behavior |
|---|---|
| Invalid config | Stop before any write. Exit code 1. |
| Drift in a generated block | Do not write that file. Continue with other files. Exit code 2. |
| A template fails to render | Stop before any write. Exit code 1. |
| A write fails | Stop. Report the files already written. A second run completes the work. |
- Log to standard error. Use one line for each file:
wrote,skipped, ordrift. --dry-runprints the changes and writes nothing.
Verification¶
- Unit tests for config validation and profile resolution.
- Golden-file tests: render a fixture repo. Compare the output with stored files.
- Idempotence test: render twice. The second run writes nothing.
- Drift test: edit a generated block.
renderreports drift and does not overwrite. - End-to-end: render a sample repo. Run the single-ticket profile on one sample ticket.
Rollback¶
- All output is in git. To roll back, revert the commit that the render made.
- To roll back the framework, set
framework_versionto the earlier tag and runstone render.
CAUTION:
--forceoverwrites drifted blocks and loses manual edits. The CLI asks for confirmation before it uses--force.
Assumptions¶
- Target repos use git and GitHub.
- The template engine is
string.Templatefrom the Python standard library (D12). A template has no logic. The CLI builds lists and conditions in code. A block placeholder ($check_steps) holds lines that the CLI builds. If the block is empty, the CLI removes its line (D29). A template-tool option (Copier) and Jinja2 were not selected, because they add a dependency. - v0 has one harness adapter (see adapters/). Other harness adapters come later.