Open identity records for humans and AI agents.
open-identities treats an identity as more than an ID. An identity can carry a human or agent name, a durable unique identifier, verified email addresses, phone numbers, integration sync references, and narrative documents such as PROMPT.md, SOUL.md, PERSONALITY.md, and ETHOS.md.
npm install -g @hasna/identitiesidentities --help
identities create --kind agent --name "Ava Example" --identifier agent:ava-example --email ava@example.com --phone +15555550123
identities list
identities show agent:ava-example
identities show agent:ava-example --verbose
identities update agent:ava-example --identifier agent:ava-renamed
identities link-email agent:ava-example ava@hasna.xyz --verified --mailery-id mailery-address-id
identities link-phone agent:ava-example +15555550199
identities machine assign agent:ava-example machine001 --purpose browserplan --slot profile-01 --json
identities browserplan reserve agent:ava-example --machine machine001 --slot profile-01 --json
identities browserplan coverage --target 8 --json
identities doc set agent:ava-example ethos "Protect user intent and identity data."
identities instructions set global --kind global-rules --title "Global Safety" --content "Never expose secrets." --rule-id safety:no-secrets --provider codewith --non-overridable --json
identities instructions list --json
identities instructions validate --json
identities instructions export ./instructions.json --json
identities instructions sources --canonical --provider codewith --json
identities agent manifest agent:ava-example --json
identities agent seed-company --docs-dir agents/hasna --json
identities eve export agent:ava-example --out ./ava-agent
identities status --json
identities media doctor --json
identities media generate-voice agent:ava-example --dry-run --json
identities media generate-profile-image agent:ava-example --dry-run --json
identities media generate-roster --voices --profile-images --dry-run --json
identities validate --json
identities status --jsonupdate <target> --identifier scheme:value renames the durable unique identifier. The previous identifier is kept as a secondary identifier so existing references keep resolving, renames onto an identifier held by another identity fail without changes, and a rename-identifier audit event is recorded.
Data is stored in ~/.hasna/identities/identities.json.
Use OPEN_IDENTITIES_STORE=/path/to/identities.json or --store <path> for isolated scripts and tests. When --store <path> is used, the CLI writes audit events to <path>.audit.jsonl unless --audit <path> is provided.
Generated media assets are stored in ~/.hasna/identities/assets by default. Use OPEN_IDENTITIES_ASSETS_DIR or --out-dir <dir> to place generated audio and profile images somewhere else.
CLI human output is compact by default so agent terminals do not ingest full identity records, document bodies, manifests, media objects, or coverage JSON unless explicitly requested. Use:
--jsonfor stable machine-readable contracts and full exported objects--verbosefor full human-side object details--limit <n>for longer human tables such aslist,machine list,browserplan list,media status, andasset list- detail commands such as
show <id> --verbose,doc get <id> <key> --verbose, andagent manifest <id> --jsonwhen a full record is actually needed
identities status --json is the public-safe machine contract for fleet
integrations. It reports store path, audit path, environment override state,
identity/contact/document/media counts, document key names, and safety flags. It
does not include contact values, document bodies, media asset paths, credential
values, or sensitive identifiers.
identities status --json emits a metadata-only reference contract for fleet
consumers. It reports package version, redacted store paths, env override
names, roster and role counts, aggregate contact/document counts, and opaque
identity refs. It does not include names, email addresses, phone numbers,
identifier values, document bodies, credentials, private keys, GitHub App
private data, or raw env values.
The package includes a deterministic Hasna company-agent roster for vertical roles such as email marketing, accounting, bookkeeping, social media management, support, sales, legal operations, security, product, design, and engineering management. Every roster identity has a canonical Greek or Roman agent name.
identities agent seed-company --docs-dir agents/hasna --jsonThe seed command upserts the roster into the selected identity store, prunes deprecated non-classical identifiers by default, and exports per-agent markdown files. Every seeded agent uses exactly one canonical agent email in the form <greek-or-roman-name>@hasna.xyz, such as calliope@hasna.xyz for email marketing, plutus@hasna.xyz for accounting, and marcus@hasna.xyz for mail operations. Roster identities do not receive secondary public or interim-domain email addresses.
Every seeded agent also receives planned media metadata:
voice: ElevenLabs voice design/TTS settings and sample textprofileImage: MiniMax image generation prompt and model settingsassets: generated media history, with file paths, checksums, provider, model, prompt, and status
Generate media for one identity:
identities media generate-voice agent:calliope --json
identities media generate-profile-image agent:calliope --json
identities asset list agent:calliope --jsonGenerate media for the full Hasna roster:
identities media generate-roster --voices --profile-images --jsonmedia doctor reports whether supported provider keys are available without printing secret values. ElevenLabs checks ELEVENLABS_API_KEY, XI_API_KEY, and HASNAXYZ_ELEVENLABS_LIVE_API_KEY. MiniMax checks MINIMAX_API_KEY, HASNAXYZ_MINIMAX_LIVE_API_KEY, HASNA_TAKUMI_LIVE_MINIMAX_API_KEY, and compatible secrets vault entries.
import { IdentityStore, getIdentityReferenceStatus, syncIdentityContactPointsAndUpdate } from "@hasna/identities";
const store = new IdentityStore();
const identity = await store.create({
kind: "agent",
fullName: "Ava Example",
uniqueIdentifier: "agent:ava-example",
emails: ["ava@example.com"],
phones: ["+15555550123"],
documents: {
prompt: "You are Ava Example.",
personality: "Direct, careful, and helpful.",
ethos: "Protect user intent and identity data.",
},
});
await syncIdentityContactPointsAndUpdate(store, identity.id, {
mailery: {
async upsertIdentityEmail(input) {
// Implement with @hasna/mailery. input.uniqueIdentifier is always non-sensitive.
return { externalId: input.email.maileryId };
},
},
telephony: {
async upsertIdentityPhone(input) {
// Implement with @hasna/telephony.
return { externalId: input.phone.telephonyId };
},
},
});
const status = await getIdentityReferenceStatus(store);
console.log(status.counts.roster.builtInAgents);Generate and attach media through the SDK:
import { IdentityStore, generateIdentityProfileImage, generateIdentityVoice } from "@hasna/identities";
const store = new IdentityStore();
await generateIdentityVoice(store, "agent:ava-example");
await generateIdentityProfileImage(store, "agent:ava-example");An identity contains:
kind:human,agent,organization, orservicefullNameand optionaldisplayNameuniqueIdentifier: a durable identifier such asopen-identities:oid_*,agent:<slug>, or another issuer-specific schemeidentifiers: additional identifiers, including sensitive identifiers when explicitly neededemails: email addresses that can be synchronized with Maileryphones: phone numbers that can be synchronized with Telephonydocuments:bio,prompt,soul,personality,ethos,capabilities,boundaries,tools,relationships,goals,context,memory,consent, andvoicevoice: generated or planned voice profile metadataprofileImage: generated or planned profile image metadataassets: generated or imported media refs, including paths, checksums, provider, model, prompt, status, and visibility metadataagent: role, model, capabilities, tools, skills, channels, schedules, and subagentstraitsandmetadata: extension fields for application-specific data
Sensitive government identifiers should be marked with sensitive: true and should only be stored when there is a legitimate operational need.
Default contact cards, agent manifests, Eve exports, and sync payloads use a non-sensitive public identifier when the canonical unique identifier is marked sensitive.
The repo currently defines adapter contracts instead of hard-coding package dependencies. The adjacent email package is open-emails, published as @hasna/mailery, with a separate @hasna/emails-sdk. The phone package is open-telephony, published as @hasna/telephony.
See docs/integrations.md for the first sync contract. See docs/browserplan.md for the BrowserPlan machine, identity, email, and profile reservation contract. See docs/media.md for voice and profile image generation. See docs/instructions.md for the instruction-source schema, precedence, export contract, and fail-closed safety rules.
OpenIdentities owns the canonical instruction-source graph for humans, agents, personas, accounts, machines, projects, sessions, global rules, and provider rules. OpenConfigs and launchers should consume this graph and render tool-native files; they should not duplicate identity/persona documents.
Instruction sources carry:
kind:global-rules,provider-rules,global-system-prompt,provider-system-prompt,identity-doc,persona-doc,account-overlay,machine-overlay,project-overlay, orsession-overlayowner: global, provider, identity/persona, account, machine, project, or session owner refsprecedence,mergePolicy(appendorreplace),replacementScope,ruleIds,targetProviders, provider compatibility, globs, source paths, editable path markers, sensitivity, provenance, and SHA-256 hashes- fail-closed safety flags: non-overridable safety sources must append, must
declare rule IDs, cannot be replaced by later sources, cannot conflict with a
duplicate rule ID, and cannot carry
secretsensitivity
CLI examples:
identities instructions set global \
--kind global-rules \
--title "Global Safety Rules" \
--content "Never expose API keys, tokens, or secrets." \
--rule-id safety:no-secrets \
--provider codewith \
--editable-source-path /home/hasna/CODEWITH.md \
--non-overridable \
--json
identities instructions set \
--kind provider-system-prompt \
--owner-kind provider \
--owner-id codewith \
--title "Codewith System Prompt" \
--content "Render through the Codewith provider adapter." \
--provider codewith \
--compat codewith:managed-block:true \
--json
identities instructions list --json
identities instructions paths --json
identities instructions show <source-id> --json
identities instructions validate --json
identities instructions export ./instructions.json --json
identities instructions import ./instructions.json --json
identities instructions sources --json
identities instructions sources --canonical --provider codewith --json
identities instructions export --canonical --provider codewith --json
identities instructions export --canonical --provider opencode --jsoninstructions list includes store-level global/provider sources, explicit
identity sources, and derived sources from populated identity documents such as
prompt, personality, ethos, and voice. The production export contract is
{ version: 1, package: "@hasna/identities", exportedAt, sources, validation, metadata }; downstream renderers should reject exports where
validation.valid is false. Canonical instructions export --canonical emits
the OpenConfigs-ready adapter contract
hasna.identities.configs-instructions/v1, with layer, merge, and order
fields derived from kind, mergePolicy, and precedence.
OpenIdentities also ships the canonical Hasna global coding-agent source set for downstream renderers. It contains one global system prompt, one non-overridable global rules source, and provider overlays for Codewith, Claude Code, Codex, and OpenCode. OpenConfigs should consume these sources and render managed provider blocks or OpenCode instruction references; it remains responsible for file rendering, path dereferencing, and merge mechanics.
The canonical set includes rules for Knowledge CLI/SDK usage, Todos plans and evidence, Mementos/Conversations/Projects source-of-truth boundaries, coordinator delegation, Codewith-native loop terminology versus OpenLoops, dispatch self-healing without tmux fallback, adversarial verification, secrets safety, commit/push secrets scans, no Co-Authored-By trailers, Bun preference, and Hasna package release-age registry hygiene.
SDK consumers can import the same data from @hasna/identities:
import {
createGlobalAgentConfigsInstructionSourceExport,
createGlobalAgentInstructionSourceExport,
} from "@hasna/identities";
const rawExportForCodewith = createGlobalAgentInstructionSourceExport({
providers: ["codewith"],
});
const openConfigsExportForOpenCode = createGlobalAgentConfigsInstructionSourceExport({
providers: ["opencode"],
});open-identities can generate Eve-compatible agent directories:
identities eve export agent:ava-example --out ./ava-agentThe exporter writes agent/instructions.md, agent/identity.json, agent/agent.ts, agent/tools/resolve_identity.ts, and skill documents derived from identity docs. The generated Eve files are derived artifacts; open-identities remains the canonical source of the identity.
bun test
bun run build
bun run verify:releaseApache-2.0 -- see LICENSE