Skip to content

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 render with 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:

  1. 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.
  2. 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 a run script (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

  1. Load the framework at the pinned version.
  2. Load and validate the repo config. Stop on the first error. Print the field and the fix.
  3. Resolve each profile: framework profile, then the repo override. Apply the rules in customization.md. Stop if a waiver removes G3 or G5.
  4. 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_allowed in the repo config. The default is all three modes.
  5. Build the component list from the profiles, the modes, the adapters, and .cornerstone/local/.
  6. Render each component to memory.
  7. Compare each rendered block with the file on disk:
  8. Same content: skip.
  9. No file on disk: write it.
  10. The disk content has the hash in the manifest: write the new content.
  11. Otherwise (a human changed the file, or wrote it before the first render): report drift. Do not overwrite. Exit code 2.
  12. Write the manifest. Keep added, owner, and review_by for existing components.
  13. 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, or drift.
  • --dry-run prints the changes and writes nothing.

Verification

  1. Unit tests for config validation and profile resolution.
  2. Golden-file tests: render a fixture repo. Compare the output with stored files.
  3. Idempotence test: render twice. The second run writes nothing.
  4. Drift test: edit a generated block. render reports drift and does not overwrite.
  5. 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_version to the earlier tag and run stone render.

CAUTION: --force overwrites 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.Template from 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.