Architecture¶
APM is structured as a four-layer architecture that separates concerns between user interaction, domain logic, external integrations, and extensibility.
Layer Diagram¶
graph TB
subgraph CLI["Layer 1: CLI"]
A[main.go — Cobra command tree]
end
subgraph Domain["Layer 2: Domain"]
B[vault.go — Vault & Entries]
C[session.go — Sessions]
D[security.go — Profiles & Alerts]
E[policy.go — Policy Engine]
F[trust.go — Trust Scoring]
G[health.go — Health Dashboard]
H[audit.go — Audit Log]
I[anomaly.go — Anomaly Detection]
J[vocab.go — Vocabulary Engine]
K[portability.go — Import/Export]
L[apmignore.go — Ignore Rules]
M[brute.go — Brute Force Test]
N[recovery_*.go — Recovery Subsystem]
O[ephemeral_session.go — Delegated Sessions]
end
subgraph Integration["Layer 3: Integration"]
P[cloud.go — GDrive/GitHub/Dropbox]
Q[mcp.go — MCP Server]
R[autofill/ — Windows Daemon]
end
subgraph Extension["Layer 4: Extension"]
S[plugins/engine.go — Step Executor]
T[plugins/manifest.go — Manifest & Permissions]
U[plugins/definitions.go — Command Definitions]
V[cloud_plugins.go — Marketplace]
end
CLI --> Domain
CLI --> Integration
CLI --> Extension
Integration --> Domain
Extension --> Domain
Layer 1: CLI¶
File: main.go (~3,600 lines)
The CLI layer uses Cobra to define the entire command tree. It handles:
- User input parsing and validation
- Interactive prompts (password input, menus, confirmations)
- Output formatting (colored terminal output via
fatih/color) - Delegation to domain and integration layers
Key Design Decisions¶
- Single binary — All commands live in one file for straightforward distribution
- Interactive by default — Most commands use interactive prompts rather than requiring flags
- Explicit session checks — Every sensitive command verifies an active session before proceeding
Layer 2: Domain¶
Directory: src/
The domain layer contains all business logic. It operates entirely in memory after vault decryption:
| File | Responsibility |
|---|---|
vault.go |
Vault struct, entry types, encrypt/decrypt logic |
session.go |
Shell-scoped session management |
ephemeral_session.go |
Delegated sessions with host/PID/agent binding |
security.go |
Profile management, alerts, email masking |
policy.go |
YAML policy loading and enforcement |
trust.go |
Per-secret trust scoring (telemetry + risk) |
health.go |
Vault health scoring algorithm |
audit.go |
Tamper-evident audit logging |
anomaly.go |
Unusual activity time detection |
vocab.go |
Note vocabulary with aliases and scoring |
portability.go |
JSON, CSV, TXT import/export |
apmignore.go |
Ignore rule parsing and filtering |
brute.go |
Brute-force test engine |
recovery_passkey.go |
WebAuthn passkey recovery |
quorum_recovery.go |
Shamir secret sharing (quorum recovery) |
recovery_codes.go |
One-time recovery codes |
Layer 3: Integration¶
| Component | File(s) | Protocol | Purpose |
|---|---|---|---|
| Cloud Sync | cloud.go |
REST / OAuth2 / PAT | Multi-provider vault sync |
| MCP Server | mcp.go |
stdio (JSON-RPC) | AI assistant vault access |
| Autofill | autofill/*.go |
HTTP (loopback) | Windows keystroke injection |
Cloud Provider Architecture¶
Each cloud provider follows the same interface:
- Init → Configure OAuth/PAT credentials
- Sync → Upload encrypted vault blob
- Get → Download remote vault blob
- Reset → Clear provider configuration
Credentials are stored encrypted inside the vault itself.
MCP Server Architecture¶
The MCP server is spawned as a subprocess by AI clients. It:
- Accepts stdio transport
- Validates bearer tokens against the vault's token store
- Routes tool calls to domain layer (vault read/write)
- Enforces permission scope checks per tool
- Manages transaction state for write operations
Autofill Architecture¶
The autofill daemon is a local HTTP server that:
- Listens on a random port on loopback
- Stores a shared bearer token for IPC
- Captures active window context via Windows APIs
- Matches credentials against vault profiles
- Injects keystrokes via
SendInput(Windows)
Layer 4: Extension¶
| Component | File(s) | Purpose |
|---|---|---|
| Engine | plugins/engine.go |
Executes plugin step pipelines |
| Manifest | plugins/manifest.go |
Validates plugin.json schemas |
| Definitions | plugins/definitions.go |
Built-in step command definitions |
| Marketplace | cloud_plugins.go |
Cloud-backed plugin distribution |
Data Flow: Vault Unlock → Save¶
sequenceDiagram
participant User
participant CLI
participant Session
participant Vault
User->>CLI: pm unlock
CLI->>Vault: Load encrypted bytes from disk
Vault->>Vault: Parse header (magic, version, profile, salt)
Vault->>Vault: Derive 96 bytes via Argon2id(password, salt)
Note over Vault: key[0:32] = encryption key<br/>key[32:64] = auth key<br/>key[64:96] = validator
Vault->>Vault: Verify HMAC-SHA256(auth_key, metadata)
Vault->>Vault: Decrypt AEAD(enc_key, ciphertext)
Vault->>Vault: Verify validator matches stored validator
Vault-->>CLI: Decrypted Vault struct
CLI->>Session: Create session file
CLI-->>User: "Vault unlocked"
Note over User: ... user performs operations ...
User->>CLI: pm add (adds entry to in-memory vault)
CLI->>Vault: Generate new salt
Vault->>Vault: Derive keys from password + new salt
Vault->>Vault: Serialize vault to JSON
Vault->>Vault: Encrypt with AEAD(enc_key, json)
Vault->>Vault: Compute HMAC-SHA256(auth_key, metadata)
Vault->>Vault: Write header + ciphertext + HMAC to disk
Vault-->>CLI: Save complete
Security Boundaries¶
| Boundary | Inside | Outside |
|---|---|---|
| Vault encryption | All entry data, credentials | Master password, keys |
| Session boundary | Decrypted vault (in memory) | Persisted data (on disk) |
| Cloud boundary | Encrypted blob (APMVAULT) | Plaintext entries |
| MCP boundary | Permitted data (per scope) | Unauthorized data |
| Plugin boundary | Permitted operations (per perm) | Unauthorized operations |
Next Steps¶
- Encryption — Detailed cryptographic design
- Vault Format — Binary format specification