Files
alkgen/AGENTS.md
T
glm-5.3-flash a91ea2ec89 docs(architecture): phase 1 base: text-generation core specs, ADRs 001-010, OQ tracker
- overview.md, core.md, emit.md, targets.md: modular spec set for the
  generalized engine (contexts + templates + partials -> text), with
  the three targets (ssr-html, bast-rust-codecs, call-handlers,
  wgsl-jit) as template sets plus emit postures
- ADRs 001-010: one core/template-set split, handlebars 6.4 strict
  substrate, sync/wasm/deterministic posture, typed contexts with
  builders, per-registry escaper, SSR library posture, typed direct
  codecs output contract, template-set ownership, feature gating,
  library-only v1
- open-questions.md: OQ-01..OQ-08 centralized tracker carrying phase-0
  residue (GN-01/02/07/09) with three deferred(scope) entries plus a
  resolved disposition for phase-0 OQ-GN-04
- tasks/architecture/: external-trigger tracker tasks paired with the
  deferred OQs (taskgraph validate passes)
- phase-0.md checklist dispositioned for OQ-GN-04; AGENTS.md lifecycle
  updated to phase 1

Verification: taskgraph validate (4 tasks OK), cargo fmt --check,
cargo test, em-dash grep clean; architecture-reviewer pass returned
zero critical issues
2026-11-06 08:18:43 +00:00

12 KiB

AGENTS.md

Operating instructions for opencode agents working in this repo. opencode auto-loads this file as instructions, overriding the built-in defaults for this project. Custom agents in .opencode/agents/ inherit these rules unless their own prompts say otherwise.

Git Workflow

Commit and push when reasonable. When a change is complete and verified (build + lint + tests pass), commit and push to origin/main without asking. This overrides the built-in default of "only commit when explicitly asked."

Commit in small, focused units: one commit per unit of work (a fix, a feature, a doc change), not one large commit covering many topics. Push regularly so work is never stranded locally.

The workflow:

  1. Make the change
  2. Verify: cargo test, cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo doc --no-deps if docs changed, cargo build --target wasm32-unknown-unknown --release if dependency/wasm-relevant code changed
  3. Inspect git status and git diff before staging; stage only the intended files, never secrets
  4. Write a concise commit message in conventional commits style: <type>(<scope>): <summary>; types are feat, fix, docs, chore, refactor, test, perf, build, ci; the scope is optional. For multi-point changes, use a summary line plus a body with bullet points and a verification block.
  5. git push origin main
  6. Report the commit hash and the verification summary

Exceptions; do not commit or push without asking:

  • The change is exploratory / speculative (you're not sure the user wants it kept)
  • The user is actively reviewing the diff and may ask for changes
  • The change touches semver-relevant public API (this crate is headed to crates.io; once published, renames/removals/signature changes on public items are breaking, while additive changes are fine)
  • You'd be force-pushing, amending a published commit, creating an empty commit, or skipping hooks

Never commit secrets, keys, or credentials. If a commit fails or hooks reject it, fix the issue and create a new commit. Do not amend the failed one.

Git identity is preconfigured (glm-5.3-flash <glm-5.3-flash@alk.dev>). Do not change git config, skip hooks, or use git commit -i.

Project Conventions (Rust / template codegen crate)

This is alkgen, the codegen engine of the alk* stack: handlebars-rust templates rendered over alktype BAST documents to produce code artifacts (binary readers/writers/validators, protocol handlers), plus plain HTML generation for alkforge's server-side rendering. Conventions apply to all work in src/ and tests/. They mirror .opencode/agents/implementation-specialist.md §Project Conventions and are repeated here so they apply to every session, not just spawned implementation agents.

  1. No comments in code unless the user explicitly asks. This is a project-wide convention. Doc comments (///, //!) are fine and expected on public API. Inline // comments only when the user asks or when a non-obvious safety/correctness constraint would otherwise be missed.

  2. Error handling: thiserror for library error types. No panics in library code. No unwrap() or expect() outside tests. If you reach for unwrap, the error path wasn't specified; stop and decide what should actually happen. Template registration/render failures are data, not crashes: a malformed template or BAST input must produce a typed error, never a panic (generated code feeds alkcall, which accepts BAST from arbitrary peers).

  3. No async: template rendering and codegen are synchronous, CPU-bound operations. No tokio, no async/await in the core. (If a future file-watch/rebuild service is wanted, that is an assembly- layer concern, not a lib concern.)

  4. WASM-clean: the crate must compile to wasm32-unknown-unknown. No filesystem access in library code (handlebars dir_source feature is off-limits in lib code; templates come from strings or include_str!). No threads, no std::time, no platform deps. If you reach for a new dependency, first verify it is wasm-compatible and worth the cost.

  5. serde_json preserve_order is load-bearing: alktype relies on it (field order in schema JSON determines packed byte order). Do not disable it and do not sort schema keys in contexts built for templates unless the template explicitly requires a sort.

  6. Strict template mode: Handlebars::set_strict_mode(true) for any registry the lib renders with. A missing variable in a codegen template must be a render error, not silently-empty output (silent gaps become compile bugs in the consumer's build, far from the cause). alkminer-v1's ShaderBuilder is the precedent.

  7. Templates are code: templates live as const &str (inline) or include_str! files, versioned in-repo, with render tests pinning their output. Changing a template changes generated code; treat template edits with the same care as source edits (tests must pin golden output before merging).

  8. Generated-code hygiene: generated artifacts start with a "Auto-generated by alkgen. DO NOT EDIT." banner (typebox-rs precedent). Rendering must be deterministic: same BAST + same templates + same options → byte-identical output (no HashMap iteration order leaking into generated code).

  9. Naming: Rust standard: snake_case for functions/variables/ modules, PascalCase for types/traits, SCREAMING_SNAKE_CASE for constants. Template registry names: lowercase kebab or snake, one name per template kind.

  10. Module structure: one module per file under src/, re-exported from src/lib.rs. Public API surface is the lib.rs re-exports.

  11. No unsafe: zero unsafe blocks. If a perf argument appears, the answer lives in the template/data-model layer, not in unsafe.

  12. No em dashes in prose. Do not use the em dash (U+2014) in source doc comments, markdown docs (docs/, README.md, AGENTS.md), agent prompts under .opencode/agents/, or commit messages. Restructure instead: split the sentence, use parentheses, commas, a colon, or a semicolon, whichever reads naturally, and vary the choice rather than converting every instance the same way. A spaced hyphen (-) is not an acceptable substitute; it reads as a different but equally recognizable writing tell. The same rule covers en dashes used as clause separators, though en dashes inside numeric ranges keep their normal meaning. Hyphens in compound words (fail-closed, client-side) are untouched. In test fixtures and scripts the rule applies to prose-y content only: comment lines are rewritten too, while fixture data, wire examples, and tool transcripts survive verbatim. Vendored third- party files under .opencode/node_modules/ are out of scope, as are rendered template outputs meant for consumer code.

Verification Commands

Run these before committing. All must pass.

cargo test                                            # full suite
cargo clippy --all-targets -- -D warnings
cargo fmt --check
cargo doc --no-deps                                   # if docs changed
cargo build --target wasm32-unknown-unknown --release # if deps/wasm-relevant code changed
cargo publish --dry-run --allow-dirty                 # before a release
grep -rn '—' src/ docs/ README.md AGENTS.md .opencode/agents/ tests/ \
    Cargo.toml                                        # must be zero hits; see convention 12

Task files (taskgraph)

Any file under tasks/ is a taskgraph task. Frontmatter is required (id, name) and its enum fields are closed sets (taskgraph 0.1.3): status: pending|in-progress|completed|failed|blocked (never done or finished), scope: single|narrow|moderate|broad|system, risk: trivial|low|medium|high|critical, impact: isolated|component|phase|project, level: planning|decomposition|implementation|review|research. A file without frontmatter is silently dropped from the graph (validate does not flag it); prose-only trackers belong under docs/. Run taskgraph validate after writing or editing anything under tasks/; full field semantics live in docs/sdd_process.md §"Task File Format" / §"Categorical Estimates".

Lifecycle Status

The project is in SDD phase 1 (architecture). Phase 0 completed with the reader POC; the project was paused 2026-09-08 and unpaused 2026-11-06. The architecture base (spec docs, ADRs 001-010, OQ tracker in docs/architecture/) was committed 2026-11-06; docs are in draft status pending OQ resolution and review finalization.

The unpause reason: alkforge (family ADR-002, gitea replacement; see /workspace/@alkdev/alkfamily/docs/architecture/decisions/002-alkforge-gitea-replacement.md) needs server-side HTML generation for its web view, and alkgen provides it. The alkforge SSR use case is simpler than the code-generation branches and is needed before them, so it jumps the queue as the first real consumer. The generality constraint it brings: the core is a text-generation engine (contexts + templates + partials → text) and must not bake reader/writer assumptions into shared core types; HTML, Rust, and WGSL are all the same shape, proven by handlebars' native case, the reader POC, and alkminer respectively.

Family ADR-002 also records the no-deformation rule for consumers: downstream asks file upstream gaps rather than forking or patching the core, so alkforge's SSR needs flow into alkgen's design, not around it.

Phase 0 output lands in docs/research/ (completed: phase-0 findings and the reader POC summary); Phase 1 output lands in docs/architecture/ (see Architecture Context). POC code never merges to main; two modes exist: branch mode (POC builds on repo code; git branch, findings merged into research docs, branch dropped) or standalone mode (POC independent of repo code; scratch project at /workspace/<poc-name>). POCs have relaxed constraints (comments/unwrap acceptable) since they are exploration tools, not production code.

Architecture Context

  • docs/sdd_process.md: the SDD process (phases, roles, task format). Phase 0 (research/POC) runs before architecture; small changes may skip the ceremony per the doc's "reasonable exceptions" clause.
  • docs/research/phase-0.md: the current phase-0 findings + OQ list. Read it before proposing design changes; extend it when research answers questions. The branch list there reflects the 2026-11-06 unpause (alkforge SSR first, then BAST readers, then call-protocol handlers, then the template-JIT core).
  • docs/architecture/: the authoritative architecture spec (started 2026-11-06, docs in draft status). README.md there is the index (doc table, ADR table, lifecycle); ADRs are numbered under decisions/; OQs are tracked in open-questions.md with stable OQ-IDs. Extend it rather than re-litigating recorded decisions.
  • tasks/architecture/: architecture-side taskgraph tasks, including the external-trigger tracker tasks paired with deferred(scope) OQs.

Reference Material (outside this repo)

  • /workspace/@alkdev/alktype: the BAST engine (crates.io 0.4.0; docs/architecture/ there is the schema/layout/validation spec).
  • /workspace/@alkimiadev/typebox-rs/src/codegen: older handlebars codegen precedent (simple context structs + inline templates).
  • /workspace/@alkminer/reference/alkminer-v1/src/compute/kernel.rs: handlebars-as-JIT precedent (strict registry, partials, render-then- compile with cache).
  • /workspace/@alkdev/alkhttp/src/adapters: from_openapi / from_jsonschema handler shapes the call-protocol codegen mirrors.
  • /workspace/@alkdev/alkcall: channels consumer; generated readers/writers/validators serve its channels.
  • /workspace/@alkdev/alkforge + family ADR-002 (/workspace/@alkdev/alkfamily/docs/architecture/decisions/002-alkforge-gitea-replacement.md): the SSR consumer; the no-deformation rule binds its asks to design input here, not forks of the core.
  • /workspace/handlebars-rust: vendored handlebars checkout (head; crates.io 6.4.4 is the pinned stable).
  • /workspace/alkgen-reader-poc: the reader POC crate (standalone mode, 2026-09-08); its Cargo.toml tracks the dep stack branch 1 exercises. Findings live in docs/research/reader-poc-summary.md.