Imported from tacticaldoll/shaahid (
AGENTS.md). Install upstream withnpx skills add tacticaldoll/shaahid. Copyright stays with the author.
AGENTS.md
Meta-guideline for AI coding agents and contributors working in this repository. Read this first,
then let openspec/specs/ and active change specs be the source of durable architecture truth.
Shaahid In One Sentence
Shaahid is a thin, sans-I/O idempotency-adjudication core: given a Deed (a
domain-supplied Seal and a content Fingerprint), it adjudicates create-or-attach
and detects structural contradictions, while making no semantic judgment of its own.
This repository is intentionally narrow. Shaahid is not a durable store, a
deduplicator that guesses identity, or a workflow engine. Durability of the Ledger
and any policy on a contradiction lie outside the pattern's shape: a pure adjudication
that owns no durable state cannot own them. They are not the identity of the core.
Architectural Axioms
Before proposing or writing code, protect these axioms:
- Adjudication core stays thin:
shaahid-contractowns the create-or-attach decision and structural contradiction detection. It does not own the durableLedger, retries, or any policy on a contradiction. - No semantic judgment in the core: semantic identity is domain-supplied as a
Seal. Shaahid adjudicates bySealequality and comparesFingerprints mechanically; it never decides whether twoDeeds mean the same thing. This is the semantic bill of purity — its cost (a wrongSealmatching itsFingerprintfails silently) is accepted deliberately, not patched by judging meaning. - Sans-I/O purity: the core exposes no
async fn, reads no ambient clock, and performs no I/O. A runtime drives it and supplies the witnessed state at the edge. - Vocabulary is governance: names such as
Deed,Seal,Fingerprint,Attestation,Ledger,Witness, andContradictionprotect the witness worldview.
Lineage
tianheng + 〔sans-I/O · OpenSpec · vocabulary-as-governance · least-commitment〕
│ inherited discipline — provenance, not coupling
▼
● shaahid
siblings: ▢ ▢ ▢ intentionally blank — this repo is sibling-blind. Which
products compose together is a consumer app's knowledge, never
a component's; naming a sibling here would leak that knowledge
and rot when the roster changes.
note: skeleton from tacticaldoll/rust-family-template.
Shaahid shares a discipline with its lineage, not code: its own crates, specs, constitution, and
release cadence. It does not import, track, or depend on any sibling product, and its governed
prose (PROJECT.md, AGENTS.md, BACKLOG.md, specs, and code comments) names none.
Document Authority
openspec/specs/is shipped architecture truth.openspec/changes/contains active proposed truth until it is synced.PROJECT.mdstates product vision, positioning, and non-goals.docs/domain-language.mdis the canonical vocabulary.BACKLOG.mdrecords settled and deferred decisions, open design questions, and candidate patterns, not mandatory phases.AGENTS.mdis operating protocol for agents and contributors.AGENTS.shaahid-law.mdis the generated, freshness-gated projection of the accepted Rust constitution incrates/shaahid-governance. The constitution is authoritative; read the projection after this file, regenerate it with its documented command, and never edit it by hand.- Other files under
docs/elaborate one topic each and yield to the documents above.
Decision provenance lives in git — the commit body and pull request that made a change record its
rationale. Forward-looking or reversed decisions are noted in BACKLOG.md. There is no separate
architecture-decision-record file class; the living documents above are the single source of
truth for current state, and git is the source of truth for why it changed.
If these documents conflict, fix the conflict through an OpenSpec change before implementing feature code.
Adversarial Review Stance
Every change passes an adversarial review at BOTH the propose and apply phases before it is committed. Actively challenge the design:
- Propose phase: Does the change make the adjudication core heavier than the
create-or-attach and contradiction mechanism requires? Does it smuggle a semantic
judgment (deciding what a
Deedmeans) into the core instead of the domain? Does it treat what lies outside the pattern's shape (a durableLedger, a contradiction policy) as core identity? - Apply phase: Does the implementation leak I/O, async, an ambient clock, or a semantic comparison into the core? Does Tianheng still bite the boundary that the prose claims?
Reject or redesign changes that pull Shaahid toward a durable store or a meaning-guessing deduplicator.
Governance and Conformance
Shaahid separates the judgment from the check on its projection.
- Governance is judgment, and lives in prose —
openspec/specs/, this file,PROJECT.md, andBACKLOG.md. Intent and meaning are decided here and stay review-governed. - Code is the projection of a judgment onto the structural plane — a
pub useset, an absentasync fn, a dependency edge, a missing trait bound. - Conformance verifies the projection still matches the judgment. It is a family: Tianheng
(structure, dependencies, source scans),
rustc(type facts), and tests (behavior). They bite the projection, never the judgment itself.
Tianheng's accepted constitution projects into AGENTS.shaahid-law.md; a freshness test byte-checks
that generated context against the live declaration, so accepted law is visible without a second
hand-maintained authority. A green gate means "no visible violation", not proof: a judgment that
casts no structural shadow stays prose, and a source scan cannot see what a macro expands to.
Before turning a judgment into a Tianheng tooth, it must pass four gates — casting a shadow is necessary, not sufficient:
- Shadow — does the judgment project into a syntactically decidable structural fact? (No → it stays prose and review.)
- Faithful — is that fact a faithful proxy, not a gameable one? (Lines of code are not thinness; a proxy invites Goodhart.)
- Stable — is the judgment stable? A tooth on a moving projection is a recurring maintenance tax and a second copy of the truth; prefer a test.
- Sync — is the extra
prose ⟷ toothcoupling worth it? The tooth is itself a second projection of the judgment, and nothing mechanically checks it matches the prose — only review does. The regress terminates in a human.
Fail any gate and the honest home is prose, review, or a test — never a faked tooth. A tooth complements review; it never replaces it. Where an accepted boundary does hold a claim, its reason is the single statement of that rule, and prose that merely restated it may be retired.
Repair code toward a violated reason; never weaken a law, baseline new drift, or change severity merely to make a check green. A deliberate law change requires explicit authority, focused violating and clean reaction proofs, projection regeneration, and adversarial review.
OpenSpec Workflow
openspec/ is the version-controlled, agent-neutral source of truth: openspec/specs/ is the
living specification of what the system is, and openspec/changes/ holds active change proposals
as delta specs. Per-agent command files (.claude/, .codex/, editor shims) are generated per
clone and never committed; generate your own with openspec init --tools <tool>.
The lifecycle is:
explore -> propose -> apply -> sync
- Explore: investigate and shape intent. Read the relevant
openspec/specs/first. Do not write feature code outside a change. - Propose:
openspec new change "<change>", then writeproposal.md,design.md,tasks.md, and delta specs with success, failure, and edge scenarios. Commit asdocs(<change>): propose <summary>. - Apply: implement against the active delta specs, one task at a time, and check a task off
only after the Definition of Done passes. Keep changes minimal and scoped; never bundle
unrelated work. Commit coherent compiling milestones as
feat(...)orfix(...). - Sync: merge verified delta specs into
openspec/specs/(agent-driven — the CLI has no sync command), thengit rm -r openspec/changes/<change>/. There is no archive: the change's content now lives inopenspec/specs/and git history. Never runopenspec archive. Commit asdocs(specs): sync <change>.
Requirement changes reach openspec/specs/ through sync, never through silent code edits.
Without agent slash commands, use the CLI:
openspec list [--json] [--specs]
openspec new change "<change>"
openspec status --change "<change>" --json
openspec instructions <artifact> --change "<change>"
Language
- Write OpenSpec artifacts,
BACKLOG.mdentries, code comments, and commit messages in English. - Converse with users in the language they use.
- Wrap Markdown prose near 100 columns; tables and code blocks are exempt.
Commit And Integration Governance
Branch Commits
- Use Conventional Commits:
type(scope): summary. - Write the subject in English, lowercase imperative mood, at no more than 72 characters.
- Use the body to record motivation, important decisions, constraints, and verification when that context exists. Do not merely enumerate changed files.
- Do not append pull request or issue numbers to the subject or body.
- Development branches may contain multiple coherent commits because the pull request is squash-merged.
Pull Requests
- Branch from
mainand open every change directly againstmain. - Make the pull request title the intended squash commit subject.
- Give every pull request a non-empty body that explains why the change is needed, what changed, consequential decisions or tradeoffs, and verification.
- Rebase the branch onto the current
mainbefore final verification. - Do not introduce a release integration branch between a change and
main.
Squash Merges
- Squash-merge every verified pull request into
main. - Make the squash commit subject exactly the approved pull request title. Hosting tools append the pull request number by default; remove it.
- Give every squash commit a non-empty, self-describing body distilled from the approved pull request body: preserve durable rationale, decisions, constraints, and verification; omit transient checklists and generated commit lists.
- Do not append a pull request number, issue number, or URL to the squash subject or body.
- Every content-changing commit on
main, including release preparation, must come from a squash-merged pull request. - Keep
mainreleasable after every merge.
Attribution
- Do not include AI, agent, model, tool, automation, or generation attribution in commits, pull requests, tags, changelogs, or release notes.
- Prohibited forms include AI
Co-authored-bytrailers,generated by,written with, model or agent names used as signatures, and tool signatures. - A
Co-authored-bytrailer is allowed only for a real human contributor.
Changelog
CHANGELOG.mdfollows Keep a Changelog and Semantic Versioning, and is a strict release ledger: it has no[Unreleased]section. Unreleased work is recorded in OpenSpec changes, pull requests, andBACKLOG.md.- Write each version's entry in its own release-preparation pull request, cross-checked against the commit history since the previous release.
- Every
## [X.Y.Z] - YYYY-MM-DDheading has a matching[X.Y.Z]: <url>footer link to.../releases/tag/vX.Y.Z.scripts/changelog-guard.shchecks this and runs in the Definition of Done.
Release Finalization
- Prepare release content in a pull request whose squash subject is exactly
chore(release): prepare X.Y.Z. - Sweep crate-level README files and other non-governed prose for stale version markers or
disposition language that
BACKLOG.mdhas since resolved, superseded, or placed downstream. - Give the release preparation squash commit a non-empty body describing scope, compatibility, metadata changes, and verification.
- Run the complete Definition of Done after that commit reaches
main. - Publish crates in dependency order, waiting for each to appear in the crates.io index before publishing its dependents. If an upload's result is uncertain, query crates.io for the exact version before retrying — a published version cannot be overwritten.
- Finalize with annotated tag
vX.Y.Zon that commit, with message exactlyrelease: X.Y.Z. - Push the tag without another commit. Release branches and empty release commits are not part of the flow.
Definition Of Done
Run these from the workspace root before checking off implementation tasks or syncing specs. This
is the single source for the gate list — README.md and docs/development-flow.md point here
rather than restating it. If a command cannot run in the current environment, report that
explicitly.
The portability gate has a one-time local prerequisite:
rustup target add thumbv7em-none-eabi --toolchain 1.88.
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all --check
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps
cargo deny check
cargo run -p shaahid-governance -- check --manifest-path Cargo.toml
cargo +1.88 check -p shaahid-contract -p shaahid --target thumbv7em-none-eabi
./scripts/changelog-guard.sh
cargo +1.88 build --workspace
CI (.github/workflows/ci.yml) runs the same gates on push and pull request. The representative
thumbv7em-none-eabi check proves the two published libraries compile without std; it does not
claim allocation-free operation or target-specific integration. Rust style lives in these checks:
rustfmt formats, clippy denies warnings, rustdoc denies documentation warnings, cargo-deny owns
resolved supply-chain policy, and shaahid-governance owns Tianheng architecture boundaries.
