- Add README.md reflecting the v0.1.0 state: 19 AlkType kinds, two layout modes, builder + AlkTypeEngine usage example (verified to compile and run), validation entry points, crate independence, untrusted-schemas guarantee, docs pointers. Mirrors the alkvault README structure. - Add AGENTS.md with alktype-specific git workflow, project conventions (no comments, AlkTypeError, untrusted schemas, overflow safety, no async, no feature flags, wasm-clean, preserve_order load-bearing, no unsafe), verification commands, and ADR/OQ index. Blocks auto-commit on semver-relevant public API changes per the crates.io 0.1.0 contract. - Add LICENSE-MIT and LICENSE-APACHE (dual MIT/Apache-2.0, matching alkvault and the Cargo.toml license field). - Cargo.toml: add readme, keywords, categories, rust-version = "1.85". - Fix broken intra-doc link in builder.rs: DiscriminatorKind -> crate::schema::DiscriminatorKind (cargo doc now warning-free). - N1 (review #002): document is_rfc3339_timestamp as non-strict in the function doc comment. Lists the specific gaps (day-of-month per month, seconds range, leap seconds) and points consumers needing strict validation to chrono/time. - N2 (review #002): document the FieldValue::Bytes-for-Record API asymmetry in the FieldValue enum doc and on read_record_value. - .opencode/agents/implementation-specialist.md: point to AGENTS.md for full convention details (matches the alkvault pattern). - review #002: mark N1/N2 resolved; all 7 findings now closed. Verification: - cargo test --release: 396 tests pass (310 crate + 86 integration) - cargo clippy --all-targets -- -D warnings: clean - cargo doc --no-deps: clean (no broken intra-doc link warnings) - cargo build --target wasm32-unknown-unknown --release: clean - cargo publish --dry-run --allow-dirty: clean
8.7 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."
The workflow:
- Make the change
- Verify:
cargo test --release,cargo clippy --all-targets -- -D warnings,cargo doc --no-depsif docs changed,cargo build --target wasm32-unknown-unknown --releaseif layout/wasm-relevant code changed - Inspect
git statusandgit diffbefore staging — stage only the intended files, never secrets - Write a concise commit message matching the repo style (see
git log --oneline -10). For multi-point changes, use a summary line plus a body with bullet points and a verification block. git push origin main- 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 repo is on
crates.io; the public surface is the 0.1.0 contract —
AlkTypeEngine,Schema/Definitions/Discriminatorbuilder types,FieldValue,AlkTypeKind,Endian,VariableEncoding,DiscriminatorKind,LayoutMode,OffsetMap/ByteRange,LayoutBuilder/PackedLayout/FieldPosition,SequentialReader,UnionDispatch,AlkTypeErrorvariants, and thedata_access/schema/tunion/materialize/validationpublic function signatures). Additive, non-breaking changes (new methods, new error variants, new builder setters) are fine to commit; renames, removals, signature changes, or behavioral shifts on existing public items are not. - 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.2 <glm-5.2@alk.dev>). Do not
change git config, skip hooks, or use git commit -i.
Project Conventions (Rust / binary struct engine)
This is a binary struct engine crate. The conventions below 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.
-
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 (e.g., "theu32at offset 1 is unaligned — correct for protocol wire formats, which pack fields tightly"). -
Error handling —
AlkTypeError(the hand-rolled enum insrc/error.rs) is the library error type. Noanyhoworthiserror— this is a library crate with a single error enum covering the three engine phases (schema, offset, access) plus validation. Never panic in library code. Nounwrap()orexpect()outside tests — if you reach forunwrap, the error path wasn't specified, stop and decide what should actually happen. -
Schemas are untrusted input — every engine path that walks a schema must return
Erron a malformed schema, neverpanic!/unreachable!. The downstreamalkcallconsumer accepts schemas from arbitrary internet peers in its hub/spoke topology, so a malicious or unsupported schema definition must produce a handleable error, not a crash. If you add a newAlkTypeKindvariant, thek if k.is_fixed_size()guard pattern inoffset_mapandlayout_builderwill catch it at runtime via the_ => Err(...)arm; listing all fixed-size kinds explicitly to restore compile-time exhaustiveness is a separate cleanup, not a blocker (review #002, L2). -
Overflow safety — use
checked_add/try_fromfor any offset arithmetic or cast that can overflow on adversarial input. Thedata_access::write_bytesu32 truncation guard (review #002, M2) is the canonical pattern: validate the cast, returnAlkTypeError::Accesson failure. Do not regress to bareas u32or+in production paths. -
No
async— the engine is fully synchronous. Notokio, noasync/.await, no async-sync primitives. Schema compilation, layout walks, read/write, and validation are all blocking, CPU-bound operations. -
No feature flags — the crate has no feature flags and no optional dependencies.
default = []inCargo.toml. If a future need surfaces (e.g.no_stdper OQ-002, or an optional strict RFC 3339 validator), raise it as an OQ/ADR before adding one. -
WASM-clean — the only dependencies are
jsonschema(withdefault-features = false) andserde_json(withpreserve_order). No platform deps, nostd::time, no filesystem, no threads. Must compile towasm32-unknown-unknown. If you reach for a new dependency, first verify it's wasm-compatible and confirm it's worth the dependency cost. -
serde_json'spreserve_orderis load-bearing — field order in the schema JSON determines byte order in packed mode, and theOffsetMap/PackedLayoutiteration order in both modes. Do not disable thepreserve_orderfeature, and do not sort schema object keys anywhere in the engine. -
Naming — Rust standard:
snake_casefor functions/variables/ modules,PascalCasefor types/traits,SCREAMING_SNAKE_CASEfor constants. -
Module structure — one module per file under
src/, re-exported fromsrc/lib.rs. Public API surface is thelib.rsre-exports; if a new public type or function needs to be visible to consumers, add it to thepub useblock inlib.rs. -
No
unsafe— the crate has zerounsafeblocks and zerounsafe externdeclarations. Bounds-checked slice access viadata_access::check_boundsandget(..)withok_or_elseis the pattern. Do not introduceunsafefor performance; the bounds-check-eliding optimization belongs in thejsonschema/serde layer, not here.
Verification Commands
Run these before committing. All must pass.
cargo test --release # full suite (~396 tests: 310 crate + 86 integration)
cargo clippy --all-targets -- -D warnings
cargo doc --no-deps # if docs changed
cargo build --target wasm32-unknown-unknown --release # if layout/wasm-relevant code changed
cargo publish --dry-run --allow-dirty # before a release
Architecture Context
docs/architecture/— the authoritative spec. Read it before non-trivial changes. ADRs are numbered; OQs (open questions) track resolved/deferred decisions.- ADR-001 — purpose, scope, "schema is the format" principle, jsonschema as the validation engine
- ADR-002 — two layout modes (packed sequential vs aligned static); the most important architectural decision
- ADR-003 — schema annotations (endianness, alignment, encoding, TUnion discriminators)
- ADR-004 — error handling and validation strategy; the
AlkTypeErrorenum, load-time build, access-time check - ADR-005 — Int64/Uint64 as first-class kinds; JSON precision caveat
- ADR-006 — reject non-final inline length-prefixed variable fields in aligned mode (prevents silent data corruption)
- ADR-007 — packed-mode read factory;
engine.sequential_reader()returns an owned fresh reader (the reader has mutable cursor state) - ADR-008 — reject TUnion in aligned mode for v1 (broken semantics)
- ADR-009 — builder API producing
serde_json::Value; resolves OQ-003 - ADR-010 —
validate_bytesonAlkTypeEngine; materializeValuefrom bytes, then validate - If a TODO references a design direction that an ADR has since decided against, the TODO is stale — remove it and align with the ADR. Do not implement the rejected design.
- OQ-001 (deferred): arrays of variable-length-element structs — blocked on a concrete consumer that needs interleaved variable-stride arrays.
- OQ-002 (deferred):
no_std+allocsupport — blocked on an embedded use case; the core engine is already allocation-free,jsonschemais the onlyallocconsumer.