ADR-014: Portable identity bundle (me.synapse)
Date: 2026-05-25 Status: Accepted (prototype shipped in v0.3) Author: Rômulo Febasi
Context
A consultant or senior IC running across N employers / clients
re-types the same person entity in every workspace and loses their
professional memory (projects touched, decisions signed,
expertise validated) every time an engagement ends. Glean’s Personal
Graph solves this conceptually but is SaaS tied to an employer’s
subscription and dies at exit. LinkedIn is coarse, public, and not
typed.
The v0.3 research brief argues this is one of the few moats SaaS structurally cannot copy: the bundle belongs to the human, not the org. We need a wire format for the bundle, a clear trust model, and an explicit list of what does and does not ship in the v0.3 prototype.
Decision
Wire format: single JSON file
The bundle is a single JSON document, conventionally named
me-<name>.synapse.json. Schema:
{
"synapse_protocol": "synapse/v1",
"kind": "identity-bundle",
"exported_at": "2026-05-25T...",
"person": {
"id": "romulo-febasi",
"title": "Rômulo Febasi",
"frontmatter": { ... },
"body": "..."
},
"attestations": [
{
"type": "project",
"id": "api-pagamentos",
"role": "tech-lead",
"since": null,
"until": null,
"title": "API Pagamentos"
}
],
"signature": null
}
synapse_protocol is the version marker: bump on any breaking shape
change. kind is identity-bundle (more kinds reserved for the
future when we share other artifacts: expertise-bundle,
curriculum-bundle).
Tar+zstd was considered and rejected: the bundle is tiny (low KB), and
the user benefit of being able to jq / open it in a text editor
outweighs any compression saving.
Source: the self: true person
Export reads the workspace’s person entity that has self: true in
its frontmatter. Exactly one is required: zero or more than one is
a clear error. Attestations are derived automatically from the
person’s memberships array (project, role, optional since /
until). Each attestation carries the referenced entity’s title
at export time so the bundle reads naturally without re-joining to
the original workspace.
Import: read-only consumption
Importing a bundle into another workspace creates / updates a
person entity. Imported persons carry an imported_from_bundle
frontmatter marker (timestamp) so they are visibly external.
Attestations attach under attested_involvement: readable but
deliberately distinct from native memberships so the consuming
workspace’s graph stays unambiguous.
The import strips incoming x-ai-* frontmatter stamps before writing:
those reference the source workspace’s audit chain, not the
consumer’s.
Signature: reserved field
signature is always null in v0.3 and the import reports the
bundle as unverified. v0.4 introduces ed25519-dalek signing:
syn identity keygencreates the user’s keypair under~/.config/synapse/identity/.syn identity exportsigns the canonical JSON (bundle minus thesignaturefield) with the configured key.syn identity importverifies against a pinned public key declared in[identity] trusted_keys = ["<base64>"].
v0.3 explicit non-goals
- No mandatory crypto:
signaturefield is reserved but unused. - No attestation revocation surface. Adding it requires either a transparency log or a re-published bundle; v0.4 picks one.
- No Sigstore-style transparency log. Reserved for v0.5+ when the user demand for cross-employer reputation justifies the operational cost.
- No HTTP discovery (
https://me.example.com/.well-known/me.synapse). Backlog. - No multi-bundle merge into one identity. v0.4.
Future direction (owner-flagged, 2026-05-25)
The owner flagged the bundle as the natural home for a curriculum-like surface built from workspace activity: “syn experience add …”, auto-derived skill counts from tag frequency, exportable as a CV. Out of v0.3 scope but recorded here so the prototype’s schema stays open to that direction:
attestationsschema is intentionally extensible (open record); future commands addskill,accomplishment,certificationkinds.- Bundle root
kindis namespaced (identity-bundle); a futurecurriculum-bundlecan layer on top with shared schema. - The
person.frontmatterfield accepts arbitrary keys today, a futureexperiencearray fits there without a schema break.
Consequences
- + Human owns their professional graph; survives any employment change.
- + Bundle is inspectable in
jqand any text editor: no vendor lock-in even on the artifact format. - + Federation with an employer workspace stays opt-in: the workspace consumes the bundle (read-only), never owns it.
- + Curriculum / CV evolution has a documented home (see above).
- − Without crypto in v0.3, an attacker who can write to the user’s filesystem can also forge bundles. Real threat for v0.4, the current threat model is “user is honest with themselves”.
- − Schema versioning lives on a single
synapse_protocolfield. When breaking changes accumulate, importer needs to learn migration. Acceptable for the prototype; ADR follow-up ifsynapse/v2arrives.
Alternatives considered
- Tar + zstd archive. Rejected: too small to benefit from
compression, kills
jqergonomics. - Sign every entity individually with ed25519. Rejected as v0.3, threat model does not warrant per-entity signing; bundle-level signature in v0.4 carries the necessary trust.
- Federate a remote bundle URL instead of a file. Rejected for
v0.3:
local-first(BR-12.1) wins; HTTP discovery is a backlog candidate when there is real demand. - Store inside the workspace
.synapse/. Rejected: the bundle belongs to the human across workspaces. Per-workspace.synapse/defeats the purpose.