spec/identity
↓ .md

repo.box Spec: Identity

Overview

Identity is the foundation layer. It answers one question: who signed this request?

Core Principles

  • An identity is an EVM address. Period.
  • The system never stores ENS names, usernames, or display names in authoritative config.
  • ENS resolution is a UI convenience, resolved on-the-fly, never persisted.
  • "Access follows a name" (e.g. treasury.dao.eth) is a groups concern, not an identity concern.

Identity Format

Identities are represented as typed strings with a prefix:

evm:<checksummed-address>

Example: evm:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

The evm: prefix exists to future-proof for other identity types (SSH keys, GitHub accounts, etc.), but EVM is the only supported type at launch.

Authentication: ERC-8128 (Hard Requirement)

All HTTP authentication uses ERC-8128 Signed HTTP Requests. No JWTs. No API keys. No session tokens. No SIWE-then-session pattern.

Every request is individually signed per RFC 9421 with an Ethereum account.

Spec References

  • ERC-8128: https://erc8128.org
  • Library: @slicekit/erc8128
  • RFC 9421: HTTP Message Signatures
  • ERC-191: Signed Messages
  • ERC-1271: Smart Contract Account verification

How It Works

  1. Client signs each HTTP request — covering method, path, body digest, nonce
  2. Signature + metadata sent via Signature and Signature-Input headers
  3. Server reconstructs signature base, verifies via ecrecover (EOA) or ERC-1271 (SCA)
  4. Server extracts signer address from keyid parameter: eip8128:<chain-id>:<address>
  5. No handshake required. Stateless verification.

Security Posture for Git Operations

Operation Binding Replay Protection
git push Request-Bound Non-Replayable
git fetch (private) Request-Bound Non-Replayable
git fetch (public) No auth required N/A

Request-Bound + Non-Replayable is the mandatory baseline per ERC-8128. Any compliant verifier must accept it.

Git Smart HTTP Protocol Mapping

Git over HTTP uses these endpoints:

  • GET /<repo>/info/refs?service=git-upload-pack — discovery (fetch)
  • GET /<repo>/info/refs?service=git-receive-pack — discovery (push)
  • POST /<repo>/git-upload-pack — fetch packfile
  • POST /<repo>/git-receive-pack — push packfile

Each request carries its own ERC-8128 signature. The server verifies independently — no session state between requests.

Smart Contract Wallets

Fully supported via ERC-1271. A multisig, a Safe, or any smart contract wallet can push to a repo. The keyid chain parameter determines which chain to verify against.

Client-Side Key Management

TBD — Fran consulting with ERC-8128 authors (Slice team) on recommended patterns. Options include OS keychain, credential helpers, browser wallet delegation.

For the git shim, identity is stored in ~/.repobox/identity and used to sign commits and determine permissions locally.

Server-Side Requirements

  • Nonce dedup store (in-memory with TTL or Redis) scoped per keyid
  • RPC connection for ERC-1271 verification (smart contract wallets)
  • No session store needed

Identity Provider Interface (Internal)

interface IdentityProvider {
  type: string;                    // "evm"
  extractIdentity(request): string; // "evm:0x1234..."
  verify(request): boolean;         // ERC-8128 signature valid?
}

EVM is the only provider at launch. The interface exists so SSH or other providers can be added later without changing the core.

Git Signing Integration

repo.box extends git's native signing infrastructure rather than running alongside it.

How It Works

  • git repobox init sets gpg.program = repobox in the repo's git config
  • user.signingkey holds the EVM address: evm:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
  • When git needs a signature, it calls box which signs with the secp256k1 private key
  • The signature is stored in the commit object — native git, not a side-channel
  • git verify-commit works using the EVM address

user.signingkey is the single source of identity. The shim reads it for permission checks. Git reads it for signing. One config key, two purposes.

Key Storage

Private keys are stored in ~/.repobox/keys/, keyed by address:

~/.repobox/keys/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045.key

git repobox keys generate creates a new key pair and prints the address. git repobox keys import <private-key> imports an existing key.

Identity Precedence

Standard git config resolution, no custom mechanisms:

  1. git -c user.signingkey=evm:0x... (per-command)
  2. GIT_CONFIG_* environment variables (per-process)
  3. .git/config in the repo (per-repo, via git config --local)
  4. ~/.gitconfig conditional includes (per-directory pattern)
  5. ~/.gitconfig global default

Multi-Agent Setup

Granting access to a new agent (requires .repobox/config.yml edit permission):

# 1. Generate a key for the agent
git repobox keys generate
# → Created: ~/.repobox/keys/0xCCC...def.key
# → Address: evm:0xCCC...def

# 2. Add the address to .repobox/config.yml (you need edit permission)
# Under groups:
#   agents:
#     members:
#       - evm:0xCCC...def

# 3. Commit the change (only @founders can edit .repobox/config.yml)
git add .repobox/config.yml
git commit -m "onboard agent-1"

Spawning agents with separate identities:

# Each agent process gets its own identity via environment
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=user.signingkey \
GIT_CONFIG_VALUE_0=evm:0xCCC...def \
codex --task "fix the auth bug"

The agent uses normal git commands. The shim reads user.signingkey from the environment, checks permissions, and signs commits — all transparently.

Audit trail:

commit a1b2c3d
EVM-signed by evm:0xCCC...def
Author: agent <agent@repo.box>

    fix the auth bug

commit e5f6a7b
EVM-signed by evm:0xAAA...789
Author: alice <alice@example.com>

    onboard agent-1

Every commit is cryptographically tied to a specific EVM address. You know exactly which agent (or human) made which change.

Security properties:

  • Agents cannot grant themselves access (editing .repobox/config.yml requires @founders permission)
  • Agents cannot impersonate other identities (signing requires the private key)
  • The orchestrator controls onboarding — generates keys, edits .repobox/config.yml, assigns identities
  • Post-hoc audit: any commit's authorship is cryptographically verifiable

Local Aliases (Address Book)

Raw EVM addresses are unreadable. Aliases give them human-friendly names — stored locally, not in the repo.

Storage

Aliases live in ~/.repobox/aliases (one per line):

alice = evm:0xAAA...123
claude = evm:0xBBB...456
roudy-piglet = evm:0xCCC...789

This file is per-machine, not per-repo. Different collaborators can have different names for the same addresses. The canonical identity is always the EVM address.

CLI Commands

git repobox alias add alice evm:0xAAA...123
git repobox alias remove alice
git repobox alias list

When setting identity, you can name yourself at the same time:

git repobox identity set <private-key> --alias alice
# → Identity set: @alice (evm:0xAAA...123)

Display

The CLI resolves aliases everywhere — error messages, logs, permission checks:

❌ permission denied: @claude cannot edit .repobox/config.yml
   (only @founders can edit .repobox/config.yml on main)
commit a1b2c3d
EVM-signed by @claude (evm:0xBBB...456)
git repobox whoami
# → @alice (evm:0xAAA...123)

If no alias exists for an address, the raw evm:0x... is shown.

Aliases vs Groups

Both use @ prefix but they're different things:

  • @founders — a group defined in .repobox/config.yml, resolves to multiple addresses
  • @alice — a local alias in ~/.repobox/aliases, resolves to one address

The CLI distinguishes by checking the alias file first, then the config groups. Groups always contain multiple members; aliases are always 1:1.

Sub-Agent Naming Convention

When agents spawn sub-agents, they use plus notation for the alias:

@claude+roudy-piglet = evm:0xCCC...789
@claude+swift-otter = evm:0xDDD...012

The parent alias + + + a random adjective-animal name. This makes lineage visible at a glance:

commit f3e2d1c
EVM-signed by @claude+roudy-piglet (evm:0xCCC...789)

    refactor database layer

The naming is a convention enforced by tooling (SKILL.md), not by the core system. The alias file just stores whatever string → address mapping you give it.

What Identity Does NOT Cover

  • Display names / ENS — UI layer, not identity
  • Group membership — See 02-groups.md
  • Permissions — See 03-permissions.md
  • "Who controls this ENS name?" — Group resolver pattern