Version. 0.1
Date. 2026-06-20
Author. Claude Code (CC) on DUNIN7-M4, read-only inspection; for Marvin Percival (DUNIN7 Operator).
Status. Findings document. Pre-scoping for a possible Stele core question; no CR. Markdown primary (technical / pre-scoping consumer). Read-only inspection of DUNIN7/stele (src/stele/) and loomworks-engine; nothing changed. Reports and characterises; recommends nothing; designs nothing.
Against. DUNIN7/stele main 8246729; loomworks-engine main 32c1a68.
The question: does Stele's identity core model a neutral, host-agnostic "human vs autonomous" distinction about a principal — something a second consumer (OVA, FORAY, an external adopter) could read without inheriting Loomworks' role vocabulary — or is that distinction only inferable through the consumer-flavoured ActorRef.kind enum?
Finding: World (c) — the core has no neutral notion of principal nature at all. ActorRef and its kind enum live entirely in the engine (the first consumer), not in Stele core. Stele core has no human/autonomous column, no is_agent/principal_type/nature flag, and no second authentication path for autonomous principals (no RFC 7523/8693 agent-auth) — every principal is one uniform identity row authenticated by the same human-shaped path (passkey + TOTP + recovery). Stele core does not branch on any of the four kind values. The human-vs-autonomous distinction is wholly a consumer-side construct; the substrate holds no neutral property today. Surfacing one would be a genuine net-new core addition, not the exposure of something latent.
ActorRef / kind — definition site and allowed valuesActorRef is not in src/stele/ at all. There is no actor.py in the standalone Stele package and no ActorRef type anywhere in Stele core. (A Phase-2 stele/actor.py existed in the monorepo but was not carried into the standalone package; actor.py stayed host-side.)loomworks-engine/src/loomworks/memory/base.py:17 — class ActorRef(BaseModel), with the field
kind: Literal["contributor", "agent", "person", "companion"] (line 66). Its docstring binds each value to an authentication path:
contributor — a human acting through a registered Contributor row (bearer-token path).person — a human acting via the session-cookie path (Phase 16).agent — an LLM-backed agent identity (instruction_version pinned).companion — the Companion acting on behalf of a person; its id carries the person's UUID (no separate companions table).loomworks-engine/src/loomworks/api/schemas.py carries a two-value kind: Literal["human", "agent"] in several request schemas (e.g. InitialContributorSpec line 739; also 758, 798, 1186) and 2–3-value wire mirrors (ActorRefResponse line 2440 = ["contributor","agent","person"]; ActorRefSchema line 4179 = ["contributor","agent"]).kind?No. What exists, and what does not:
PrincipalRow (src/stele/models.py:48) columns: id, display_name, totp_secret, first_login_at, last_presence_proof_at, created_at, updated_at. There is no is_human / is_agent / is_autonomous / principal_type / principal_kind / nature column (targeted search across src/stele/ returned zero hits).Principal view (src/stele/registry.py:27) carries id, display_name, and two optional auth-lifecycle timestamps — and deliberately nothing more (the no-credentials invariant). No nature attribute.principals, webauthn_credentials (passkeys), recovery_codes, plus the totp_secret column on the principal. There is no separate agent-credential class or column — no kind/type/grant/jwt/bearer field on any Stele row. Every principal authenticates the same way.So Stele core carries no representation — column, enum, flag, or derived property — of whether a principal is human or autonomous.
kind values are core identity-concepts vs first-consumer vocabulary?All four are first-consumer vocabulary; none is referenced as a discriminating value inside Stele core logic.
| Value | Hits in src/stele/ | What they are |
|---|---|---|
| person | 43 | All generic substrate naming — person_id, person_totp, the _PersonRow stub, "the person's only passkey". The substrate's ordinary word for a principal; never used as a discriminating kind value. |
| companion | 1 | The English word in webauthn.py:245 ("its companion pending store") — unrelated to the Companion identity. |
| agent | 1 | A docstring aside in api.py:19 ("Bearer for an agent"). |
| contributor | 2 | Docstring prose in person_totp.py ("the two-step contributor TOTP flow"). |
Zero Stele-core logic branches on any of the four values. By contrast, the engine branches on kind == "agent" at many sites — e.g. engagement/assertions.py:168, engagement/creation.py:802, engagement/manifestation.py:280, engagement/shaping.py:267, delegation/service.py:73, and the data-layer commit_assertion agent-reject described at memory/base.py:30. Every human-vs-autonomous decision lives consumer-side.
(The distinction is enum-only and enum-is-engine-side, so this is the relevant case. Reported as seams; no design, no recommendation.)
PrincipalRow (src/stele/models.py), added by the Stele baseline migration (migrations/versions/0001_baseline.py), and surfaced (or not) on the Principal view (src/stele/registry.py).ActorRef.kind == "agent" (the sites in §3); those could optionally map down to a core property, but none requires it.src/stele/ for jwt | 7523 | 8693 | token-exchange | bearer-assertion | client_assertion | grant_type returned no hits.webauthn.py), TOTP (person_totp.py), recovery codes (recovery.py), and a Fernet session (session.py) whose payload is person_id + totp_verified — no actor-kind, no agent grant, no machine-credential path.agent) concept is created and used entirely consumer-side. The RFC 7523/8693 path that would imply a core-level split does not exist in Stele core, so §5 does not answer §1 affirmatively.person+agent neutral with companion+contributor as the consumer leak (axis-separation) — No. This would require person/agent to be modeled in Stele core as neutral identity concepts. They are not — none of the four values, not even agent, exists in Stele core; the entire enum is engine-side.kind, no nature flag, no agent-auth. The human-vs-autonomous distinction is held entirely by the first consumer (the engine), expressed two ways there (the 4-value ActorRef.kind and a separate 2-value ["human","agent"] API binary). A neutral core property would be net-new substrate, not the surfacing of something latent.DUNIN7 — Done In Seven LLC — Miami, Florida Stele core — principal-nature neutrality — investigation — v0.1 — 2026-06-20