Version. 0.1
Date. 2026-07-17
Author. Claude Code (CC) on DUNIN7-M4, read-only inspection; for Marvin Percival (DUNIN7 Operator).
Status. Findings document. Grounding investigation across four products; no CR. Markdown primary (technical consumer). Grounded in this session's own reads of ~/stele (tag v0.3.0), ~/stele-agentic-id (V1 frozen, V2 in build), ~/grantha (main 0292dcd), and ~/loomworks-record/protocols/ova/, via four parallel sub-agent source-reads, each spot-checkable against the cited files; nothing changed. Reports and characterises; recommends nothing; designs nothing; resolves nothing.
What this reports. How agent identity works in the DUNIN7 stack, alongside the human identity system in Stele: whether Stele has an agentic identity system at all; if so, how an agent authenticates (what it presents, what verifies it, what it receives); how an agent's authority is scoped and to whom its actions are attributable; how the agentic system relates to the human one; and how both sit against OVA and GRANTHA — including where those relationships are settled and where they are not.
What was found. There is no agentic identity system inside Stele. ~/stele authenticates humans and nothing else; agent identity is deliberately out of scope and lives in a separate sibling product, Stele Agentic ID (~/stele-agentic-id, repo DUNIN7/stele-agentic-id), which is real and mostly built (V1 frozen, 408/408 tests; V2 in build). An agent authenticates by local-signature mint (it presents a signed credential carrying its chain of hops), which a Verifier checks by a bounded chain-walk against a signed ~60-second registry statement, returning a verdict, not a token. An action is attributable to the agent (nature: autonomous), always cryptographically rooted — but to a human only through an optional, usually-null acts_for UUID, whose consent/binding model is explicitly undecided. The agentic product shares no principals table and no session with human Stele — only a neutral stele-core package. OVA does not define agent identity (it is an anonymous, blindness-focused on-chain access-control protocol that knows nothing about actors) and is no longer the stack's authorizer either; GRANTHA owns authorization. The four-way division — Stele Agentic ID = identity, GRANTHA = authorization, FORAY = notary, OVA = displaced — is clean in intent, but several seams between the products are explicitly marked undecided, and OVA's current place is unstated.
What decision rests on it. This is grounding, not a build order — no CR is attached. It grounds any decision that assumes agent identity in the DUNIN7 stack: in particular, letting a Companion or other agent act for a human inside Loomworks (which needs the acts_for binding that is not yet decided), integrating Stele Agentic ID as the identity fabric, and any reliance on the GRANTHA/OVA product boundaries. Its job is to make plain what is built vs. spec-only vs. undecided, and where the boundaries actually sit, so a later decision is not made against a boundary that only looks settled.
Out of scope. This designs, builds, recommends, and resolves nothing. It does not adjudicate the open boundary questions (OVA's current role, the two "Boundaries" stacks, human↔agent federation) — those are Operator/portfolio decisions. It does not audit FORAY's internals beyond its role as the anchor both sides depend on, and it does not assess human Stele beyond what is needed to contrast it. Read-only; nothing changed.
One honesty caveat. Two of the four systems here are documentation, not running code: OVA's build has not started, and GRANTHA is docs-only and — by its own Ratification Ledger's admission — largely reconstructed from memory of an earlier draft, with only four items Operator-ratified. Where a relationship rests on such a doc, this report says so rather than presenting it as settled.
Separate. Inside ~/stele there is no agent (non-human) identity or authorization mechanism at all — no agent principal type, no delegation, no scoped-authority grant, no machine/service identity. The identity model is single-typed: every row in the principals table is a human. The repo states this itself:
> "Agent identity — AI agents as authenticated principals, not just humans — is something we're exploring for a future, separate product alongside Stele." — ~/stele/CHANGELOG.md (Known limitations)
The three occurrences of "agent" in ~/stele are all unrelated to an in-repo agent identity: (a) "AI coding agent" = the developer tooling that mounts Stele; (b) "agent" as a bearer-token transport shape (Authorization: Bearer, "agent-friendly" only in the sense of how a token arrives — the token still encodes a human person_id); (c) the CHANGELOG note above deferring it elsewhere.
The agentic system is Stele Agentic ID.
DUNIN7/stele-agentic-id (private)./Users/dunin7/stele-agentic-id.spec/stele-agentic-id-spec_V12.md, REQ-001–102, 408/408 tests, wire format frozen v1.0). V2 (spec/v2/…-v0_4.md) is in build, not complete.decisions/agentic-id-decisions-v0_14.md).The model is local-signature minting + bounded chain-walk verification against a signed registry statement. There is no per-action token-issuer round-trip. (Charter, V12: "agents as first-class principals, creation by local signature … verification by bounded chain walk.")
What the agent presents — a signed credential carrying its whole chain.
SigningSDK.mint() (packages/agentic-id/src/agentic_id/signing_sdk.py): "no registry call, no network call." A mint generates a fresh Ed25519 keypair and a UUID aid, stamps counter, iat/exp, issuer, root_id, depth, and signs the canonical payload twice under domain-separated contexts (a credential-context signature and a hop-context signature).{…payload, "sig": credential_sig, "chain": [hop, hop, …]} — the chain is the list of parent hops back toward the root. Every mint also appends one durable write-ahead-log line before returning.What verifies it — the Verifier SDK doing a signature/chain walk, anchored on a signed registry statement.
Verifier.verify() (verifier.py) is fail-closed ("verify() never raises; every call appends a WAL event").Registry.statement(), registry.py) passed into verify(), checked against the registry's pinned public key.depth+1 verifications total) → attestation co-signature.
What the agent receives — a verdict, not a token. VerifyResult(ok, reason, aid, depth, …). A pass is ok=True; a failure carries a closed-registry reason code (ROOT_REVOKED, CLAMPED, UNWITNESSED_MINT, COUNTER_OUT_OF_RANGE, INVALID_STATEMENT_SIG, …). No bearer token is issued back.
Named pieces: Mint (SigningSDK.mint), Verify (Verifier.verify), Statement (Registry.statement, the signed cacheable read-path anchor: key mode, registered operational credentials, allocated counter ranges, depth bound, status), Reconcile (Reconciler, an out-of-band continuity checker catching off-books mints and counter-range gaps), and the Attestor/witness co-signature (the "Observance Law": an SDK with no witnessing accumulator refuses to mint with ACT_ONLY; attested environments require a witness_sig).
Scope — root subtree + counter allocations, with subset-nesting and a clamp/kill lane.
root_id; every hop chains back toward root:<root_id>. Depth counts every hop; default bound 4, hard max 8.COUNTER_OUT_OF_RANGE against the statement's allocated_ranges.delegate_sub_range()) carves counters off the top of the parent's unconsumed range and stamps a delegated_range into the child's signed payload; the verifier enforces full-chain nesting — every delegated_range ⊆ its parent's, topmost ⊆ root allocation. (This is the fix for the deep-chain nesting exploit found in integration review.)CLAMPED (freshness window ~30s, fail-closed past it with REVOCATION_STATUS_STALE); kill/revoke = irreversible, gated behind a human-held or pre-authorized GRANTHA grant, sets root status='revoked' → ROOT_REVOKED.Attribution — to the AGENT, with an optional, explicitly-scoped pointer to an acted-for human.
nature: "autonomous" (the PrincipalNature enum has exactly two members, human / autonomous). The acting party is the agent/root itself.acts_for UUID — "the ultimate acted-for principal by UUID" — which is usually null (a normal chain has acts_for is None). Humans are "referenced by UUID only"; acts_for is a bare reference, not an authenticated human credential.acts_for is explicitly undecided. V2 Exclusions: "Act-for consent/binding model: deliberately not decided in V2; trigger — the next credential-format change." So what it means for an agent to legitimately act for a human, and how that is consented to or verified, is spec-open, not built.
Plainly: an action is provably the agent's, and provably rooted; it is not provably a given human's unless acts_for was set, and even then the binding semantics are an open question.
Entirely separate — separate repo, separate data model, separate crypto surface. Positioned as the "Sibling Resolution."
roots, operational_credentials, revocations tables in registry.py). It does not share Stele's principals table. Human Stele's principals (UUID, display_name, totp_secret; no email, no roles) is untouched by it.stele-aid/…/v1) are the agentic product's own.stele-core package — the PrincipalNature enum (human / autonomous) and language-neutral wire specs, "nothing federation-shaped." The human-Stele seam is scoped to "UUID reference of human principals; shared stele-core package"; "any human-identity function" is explicitly out of scope.DUNIN7/stele is never automatically modified from work done here."What OVA is. OVA is a decentralized, privacy-preserving access-control protocol — a "based ZK application" on the Kaspa blockDAG. Its defining property is blind authorization: access is granted through cryptographically indistinguishable on-chain objects called "eggs" (real / chaff / nest, serialized identically) plus ZK proofs that let a requester prove they satisfy an ACL without revealing which condition or any identity. "Ova" is Latin for eggs — not an acronym (no doc expands it; the egg is its single building block).
Where it lives. Canonical home is ~/loomworks-record/protocols/ova/ (its README says it needs no separate repo — "OVA's committed home is here"). Spec lineage V1→V3.2. Current authored spec is V3.2 (2026-06-23); the Forge-blessed spec is still V2. The build is not started ("specify yes, build no"), gated behind a formal verification program and Kaspa mainnet activation. (The F-numbers in the design dir — F-1/F-3/F-4 — are design findings, not spec versions.)
Does OVA define agent identity or authorization? No, on both counts — and this is stated on both sides.
So OVA relates to the identity question mostly by exclusion: it is neither the identity system nor (now) the authorizer. Its committed posture is blindness — deliberately not knowing who is acting.
First, what GRANTHA is, since it is the third corner: a FORAY-anchored authorization system for agents and other principals — grants, machine-speed reversible containment (clamp), human-gated revocation (kill), tamper-evident audit (Discovery Record v0.14). One primitive — the grant ("these holders may do this thing, to this resource, while these conditions hold"); a group is many holders, a role is a grant over a capability, and "a grant over the grant-issuing capability is administration." Access checks are local, microsecond, consult-not-enforce ("GRANTHA authorizes; it never enforces" — every enforcement point is a local governor that must ask and honor the answer). It does no ZK (that thesis was dropped and Operator-ratified); proofs/anchoring are FORAY's job.
The historical overlap was real and is documented. OVA once claimed both identity and authorization: "OVA agent identity" and the protocol triangle "Loom remembers, OVA authorizes, FORAY audits" (AIF playbook comparison, May 2026); the entire May-2026 FORAY/OVA integration investigation is built on "OVA authorizes" and never mentions GRANTHA (GRANTHA is newer). Stele Agentic ID's "agent identity" role overlapped OVA's identity claim.
What is now settled (the clean part):
| System | Owns | Refuses | |---|---|---| | Stele | human authentication (who a person is) | authorization | | Stele Agentic ID | agent identity/authentication — "who an agent is, who made it, who it acts for" | authorization | | GRANTHA | authorization — grants, clamp/kill | identity/authentication | | FORAY | tamper-evident notary/anchor ("witnesses, never decides, never enforces") | deciding/enforcing/authorizing | | OVA | (former authorizer + identity) — displaced from both; current role unstated | authorization (per Decision J1) |
What is unsettled / open — stated plainly, not reconciled:
capability_ref 64-byte identifier floor, ratified 2026-07-15.[OPERATOR-SHEET] ("adopt-with-reservation"); Stele Agentic ID's live FORAY anchoring (V2 Cycle 3) is gated on an unanswered FORAY seam request and still runs against a mock intake.
Do not read a clean hierarchy into corner-6. The tidy four-row table is the settled intent; the docs themselves repeatedly mark the connective tissue [OPERATOR-SHEET], UNSTABLE, [RECONSTRUCTED — not on record], and "Decider: Operator, portfolio-level." And GRANTHA's whole design set is, per its own Ratification Ledger, largely memory-reconstructed with only four ratified items — so its confident-sounding boundary statements are recommendations more than settled law.
~/stele: no agent identity of any kind (by design; deferred to the sibling product).acts_for consent/binding model (how an agent legitimately acts for a human): explicitly not decided; not built.stele-core is shared today.DUNIN7 · Stele inspection — agentic identity report · v0.1 · 2026-07-17 · inspection only, nothing built or modified.