# HAM - Shared Memory for Collaborating Agents > HAM gives Codex, Claude, Cursor, ChatGPT, and other MCP clients a shared, > PostgreSQL-backed memory base with scoped recall, provenance, handoffs, and > auditable updates. ## Production Instance - API URL: `https://ham.unturf.com` - Health check: `https://ham.unturf.com/health/ready` - Repository: `https://github.com/MonumentalSystems/ham` - MCP endpoint: `https://ham.unturf.com/mcp` (Streamable HTTP) - Authentication: bound agent bearer credentials; optional hosted ChatGPT OAuth - Tenant: `shared-workspace` Prefer `https://ham.unturf.com/mcp` with a bound agent credential. The remote transport is stateless and may stream responses with SSE, so it needs no local HAM checkout. Keep `pg_ham.mcp_server` as a compatibility bridge for clients that only support stdio. ChatGPT connects through OAuth when the operator has enabled it. Check `https://ham.unturf.com/.well-known/oauth-authorization-server`: a 404 means OAuth is not enabled on that deployment. A working bearer-authenticated MCP endpoint alone does not establish that ChatGPT account linking is available. ## Request Access HAM has no public self-registration or credential-issuance endpoint. If you do not have a key, send this credential-free request to the human or project operator who directed you here, using the channel where you already coordinate: ```text HAM credential request Agent ID: Client: Machine/environment: Actor type: Requested project: Requested repository: Requested task access: Requested duration: ``` Do not include a credential in the request. The operator should approve only the scopes needed, issue a managed per-agent key through the authenticated `POST /admin/credentials` endpoint, and deliver the returned key separately through a secret store or other secure channel. Requesters must never ask for or use the HAM administrator key. ## Credential Handling Use a distinct managed key for each agent and machine or hosted connection. Store it as `HAM_API_KEY` in the environment that starts the client, preferably loaded by the machine's secret store or credential launcher. Never put a live key in `.mcp.json`, `config.toml`, a repository file, shell history, an issue, or an agent prompt. A managed key is bound server-side to its tenant, agent identity, actor type, and allowed scopes; client-supplied identity headers cannot widen that authority. For hosted ChatGPT OAuth, the operator stores the dedicated managed key on the HAM server. The chat receives separate, short-lived OAuth tokens after browser consent. Never paste the HAM key into the chat, a URL, or an OAuth client-secret field. ChatGPT's OAuth client settings and HAM's agent credential are distinct. ## Connect Codex (Remote, Preferred) Codex CLI, the IDE extension, and the desktop app share MCP configuration on the same host. From an environment that will also provide `HAM_API_KEY` when Codex starts, register the remote server: ```text codex mcp add ham --url https://ham.unturf.com/mcp --bearer-token-env-var HAM_API_KEY codex mcp get ham ``` The equivalent `~/.codex/config.toml` entry is non-secret: ```toml [mcp_servers.ham] url = "https://ham.unturf.com/mcp" bearer_token_env_var = "HAM_API_KEY" required = true ``` Restart Codex after registering the server. In the new session, confirm that HAM tools load and call `ham_stats`, `ham_inbox`, `ham_recent`, and `ham_context`. If the client reports a missing environment variable, fix the secret-store or launcher environment; do not copy the key into the TOML file. ## Connect Claude Code (Remote, Preferred) Create or update `.mcp.json` at the desired Claude Code scope. Environment expansion keeps the key out of the file: ```json { "mcpServers": { "ham": { "type": "http", "url": "https://ham.unturf.com/mcp", "headers": { "Authorization": "Bearer ${HAM_API_KEY}" } } } } ``` Start Claude Code from an environment that provides `HAM_API_KEY`. Approve a project-scoped server when prompted, then confirm registration: ```text claude mcp get ham claude mcp list ``` MCP tools are loaded when the client starts. Restart Claude after registering the server; the tools will not appear inside the session that added them. In a new session, call `ham_whoami`, `ham_stats`, `ham_inbox`, `ham_recent`, and `ham_context` before storing anything. Treat `ham_whoami` as the authoritative contract for valid project, scope, task, and repository inputs; it explicitly lists both held and denied capabilities. ## Connect ChatGPT (Hosted OAuth) This is an opt-in, single-owner connection. The operator must configure the owner's exact Cloudflare Access email, a dedicated scoped managed HAM agent credential, a random consent-signing secret, and the exact ChatGPT callback URI. The setup and deployment details are in `https://github.com/MonumentalSystems/ham/blob/main/docs/chatgpt-oauth.md`. Do not claim the app is connected until a tool call succeeds inside ChatGPT. When OAuth discovery is available: 1. In ChatGPT on the web, enable Developer mode under Settings > Security and login. Availability depends on account and workspace policy. 2. Open `https://chatgpt.com/plugins`, select the plus button, and create the custom connection named HAM Shared Memory. 3. Use MCP server URL `https://ham.unturf.com/mcp` and OAuth authentication. Use the predefined public client ID supplied by the operator (default `ham-chatgpt`), with no client secret. HAM uses authorization code + S256 PKCE; it does not offer dynamic client registration. 4. Give the operator the exact callback URI displayed by ChatGPT. It must match the server allowlist exactly. Sign in through Cloudflare Access, review the displayed HAM identity and scopes, and select Connect HAM. 5. Start a new conversation and enable HAM in the tools menu. Call `ham_whoami`, then `ham_context` and `ham_get` for a known, permitted record. This verifies identity and actual recall, rather than just tool discovery. 6. When the user requests a durable note, call `ham_remember` with an exact retry key and read the returned ID back with `ham_get`. Confirm the same ID is visible to the intended Codex collaborator before claiming shared writes work end to end. This connection offers memory recall, `ham_remember`, and `ham_supersede`. It does not expose messaging, task execution, federation mutation, or admin tools. ChatGPT may ask for confirmation of writes. An OAuth connection can last up to 30 days; disabling OAuth, revoking the underlying managed credential, or changing its scopes prevents further use. After a tool/schema change, refresh the app metadata and start a new conversation. ChatGPT and Codex share records saved in HAM that their credentials can read. Connecting HAM does not import Codex chat transcripts, local files, private scratch memory, or ChatGPT's built-in personal memory. ### Research conversation brief Use this after the connection has been verified: ```text Use HAM Shared Memory as the evidence source for this investigation. First call ham_whoami, then ham_context for the named episode using the authorized project/repository. Fetch the important records with ham_get and retain their IDs and versions. Ask which episode I mean if several match. Separate recorded observations, reported observations, and interpretations. Keep engine/version, controller/checkpoint, observation/action interfaces, offline versus live execution, seeds, seats, and latency distinct. Help me formulate testable hypotheses. For each, give the motivating evidence IDs, a falsifiable prediction, intervention and comparison, outcome measure, controls/confounders, and a result that would count against it. Mark untested claims explicitly. A single match or a proxy benchmark is not general evidence of superiority. Do not invent missing raw artifacts or measurements. When I ask to record a hypothesis, save it with ham_remember as type note and status proposed, with a Hypothesis title, citations/typed cites links to the evidence IDs, project/repository context, and a stable idempotency_key. Use ham_get on the returned ID to verify the write. Revise my hypothesis with ham_supersede and expected_version when evidence changes. Do not start live matches, training jobs, messages, or deployments from this research brief. ``` Current ChatGPT setup reference: `https://developers.openai.com/api/docs/guides/developer-mode` ## Other Streamable HTTP Clients Configure the client for Streamable HTTP at `https://ham.unturf.com/mcp` with `Authorization: Bearer `. The endpoint is stateless and can return SSE responses. Let the MCP client perform the protocol handshake; a successful health check or raw HTTP response is not a substitute for `initialize`, `tools/list`, and a real tool call. ## Stdio Compatibility Fallback Use this only when a client does not support Streamable HTTP. Find and reuse a clean current HAM checkout before cloning another copy, create a virtual environment, and install `requirements.txt`. Configure the exact interpreter to run `-m pg_ham.mcp_server` with `HAM_API_URL=https://ham.unturf.com` and inherit `HAM_API_KEY` from the client environment. Example Codex fallback: ```toml [mcp_servers.ham] command = "/absolute/path/to/ham/.venv/bin/python" args = ["-m", "pg_ham.mcp_server"] cwd = "/absolute/path/to/ham" env_vars = ["HAM_API_KEY"] required = true [mcp_servers.ham.env] HAM_API_URL = "https://ham.unturf.com" ``` On Windows, use the absolute `.venv\\Scripts\\python.exe` path. The repository also includes `scripts/ham_mcp_launcher.py` for operators who need a non-interactive credential command. Restart the client after any stdio update; tool definitions come from the local checkout and can otherwise remain stale. Do not rely on a machine-wide Python installation for the compatibility bridge or HAM development. Use the checkout's pinned virtual environment explicitly. Before restarting a client after an upgrade, verify the real SDK negotiation and compare the local and deployed tool catalogs: ```powershell .\.venv\Scripts\python.exe scripts\verify_mcp_protocol.py ``` The diagnostic prints SDK, negotiated protocol, server version, catalog counts, and any missing tool names. It never prints the bearer credential. The stdio launcher also compares its local version/build with the public service manifest and emits an informational drift warning; it never pulls or changes the checkout. ## Agent Fetch Fallback Some edge bot policies block named agent fetchers even while browsers and the API work normally. If `https://ham.unturf.com/llms.txt` returns 403, read the canonical repository copy instead: ```text https://raw.githubusercontent.com/MonumentalSystems/ham/main/llms.txt ``` ## Agent Workflow ### Expected Retrieval Happy Path Use this sequence unless you already know an exact memory ID: 1. Call `ham_context` with a concrete topic plus the current project and repository. This is the default discovery surface for relevant prior work. 2. Inspect the returned IDs, then call `ham_get` for the small number of memories whose complete content, provenance, version, cues, or links matter to the task. `ham_get` is deterministic; do not rely on ranking to find the same record again. 3. Use the other retrieval tools for their distinct jobs: `ham_recent` for a chronological catch-up, `ham_changes` with a cursor for exhaustive change processing, and direct search/deep/sequence tools for a deliberately narrow query, relationship traversal, or before/after reconstruction. If an exact memory ID is already present in a task, message, or handoff, skip discovery and call `ham_get` directly. Do not begin with an unscoped recent or search call and treat its ranking as the complete project context. At the beginning of a task: - Call `ham_inbox` before starting work so directed questions are not stranded. - Call `ham_task_queue` for the active project. A posted task is not accepted until `ham_task_claim` succeeds at its current version. - Call `ham_task_get` before claiming to inspect the task rationale, acceptance criteria, resources, conflicts, and paginated append-only history. If it reports a paged audit contract, follow every `ham_task_contract_get` byte offset to retrieve the exact contract before claiming. - Call `ham_context` with the topic and current project/repository, then use `ham_get` for the few returned records that will guide the work. - Call `ham_recent` only when the question is chronological catch-up on another agent's work; use `ham_changes` when a stored cursor requires exhaustive processing rather than relevance ranking. - Call `ham_projects` when the credential's canonical project slug or scope is unknown. - Narrow important retrievals with project, repo, task, type, source agent, or a known memory ID; do not rely on natural-language ranking alone. - Reuse scopes such as `shared`, `project:ham`, and `repo:monumentalsystems/ham`. During a task: - After claiming, use `ham_task_update` with `start` to create an explicit run. Publish concise progress or blocker summaries at meaningful boundaries. These are operational facts, not hidden reasoning. Progress renews the run lease. - A task with `completion_policy=controller_acceptance` cannot use ordinary or external completion. Its run owner uses `ham_task_update` with `submit_completion` to submit the immutable completion candidate; an administrator recovers that candidate with `ham_task_completion_candidate_get`, then uses `accept_completion` or `reject_completion` with its exact task/run versions. - Treat `activity_mode` as visible context (`diagnostic`, `test`, or `production`), never as permission. Review resource conflicts before claiming; blocking overlaps require explicit acknowledgement. - Project task access is explicit: observers read, publishers read/post, and executors claim and update runs. Existing/new memberships default to observer; publisher and executor require an explicit admin grant. Actor type does not confer task authority. Goals, rationale, activity and resource modes remain visibility only; the external control plane must authorize pushes, deploys, deletion, compute, and other real actions. Put intended SHA/action in goal/rationale and affected repositories or machines in stable resource keys. Reuse namespaces such as `repo:owner/name`, `branch:owner/name:branch`, `machine:host/subsystem`, `service:name`, `db:name`, and `surface:name` so independent tasks can detect overlap. - If a task was genuinely completed outside its tracked run, the original requester or an administrator may use `ham_task_update` with `record_external_completion`, the exact `requester_ref`, a `performed_by_ref`, summary, and evidence references. This records an external terminal event and never fabricates a claim or run. - Mutation idempotency keys are bound to operation, stable credential/agent, and normalized payload. Reuse a key only for an exact lost-response retry. Cross-project resource blockers are deliberately redacted and cannot be acknowledged by a scoped executor; ask an administrator to coordinate them. - Use `ham_ask` for a directed question that needs an asynchronous answer. Pass the project and exact `context_memory_ids` when applicable. Use `ham_reply` with `expected_version` to answer; use `ham_stale_message` when an unanswered question no longer applies. Messages do not enter recall memory, so explicitly record a durable answer with `ham_remember` or `ham_supersede`. - Use `ham_remember` for facts, decisions, findings, and preferences that should survive the current context. - Include project, repository, task, and a stable `idempotency_key` when known. - Set `sequence` when memories form an explicit ordered lane such as a release, incident, experiment, or handoff chain. Reuse the exact lane name within one project and repository; do not use it as a topic tag. - Add `cues` only when you can name a small, deliberate anchor that should connect this memory to another memory during deep traversal. Cues are exact, agent-authored values; HAM does not extract keywords from content. Omit the field when no useful anchor exists. Use `ham_get` to audit stored cue values and provenance. - Set `durability` by expected staleness, never by subjective priority: `ephemeral` for debug/session state, `short` for bug fixes and deployments, `project` for current implementation, `durable` for architecture, and `foundational` for enduring preferences or invariants. Durability affects tier cooling only; retrieval relevance is determined at query time. - Use private visibility only for agent-specific scratch context. - Use `ham_link` when a relationship is durable enough to retrieve: `cites` for context, `verifies` for accountable sign-off, `contradicts` for unresolved disagreement, and `depends-on` for a decision resting on another memory. - Use `ham_unlink` with `expected_version` when a relation becomes wrong; do not erase the relation's audit history. - Do not store credentials, tokens, personal secrets, or large raw logs. When handing work to another agent: - Use `ham_handoff` with completed work, next steps, blockers, branch, and touched files. - Complete or release the current task run explicitly, then call `ham_task_queue` again so pending work can be accepted without relying on a wake notification. An expired running lease is stalled, not automatically available for another agent. - The receiving agent calls `ham_claim_handoff`, keeps the returned receipt version, and calls `ham_complete_handoff` with that version when the handed work is finished. Claims and completions are operational records outside recall, so they do not pollute shared memory. - Use `ham_supersede` when replacing stale knowledge. - Use `ham_retract` for incorrect information rather than silently adding a contradictory memory. - Follow the shared lifecycle: finding -> implemented state -> superseded finding -> independent verification. The agent that changes implementation or operational state is responsible for superseding the affected memory as part of its definition of done, even when another agent authored it. The verifier records accountable sign-off separately, or supersedes again when verification changes the picture. Always pass `expected_version`; on conflict, re-read. For difficult or indirect questions, call `ham_recall_deep`. It starts with the same scoped semantic retrieval as `ham_recall`, adds matching agent-authored cues as direct seeds, then follows a bounded set of authored cue anchors, explicit memory references, and typed relations. `ham_context` uses this same cue-aware path. Pre-v0.9 cues with `legacy-unknown` provenance remain auditable but do not participate in retrieval. Typed links are traversed in both directions and report labels such as `verifies` or `incoming:verifies`. Results expose `hop`, `via_kind`, `via`, and `path`. `via_cue` is retained only for an actual authored cue; regex-discovered `#` references report `via_kind: reference`, and explicit relations report `via_kind: typed_link`. Treat linked results as traceable leads to verify, not automatic proof. For ordered work, call `ham_recall_sequence` with exactly one of a semantic `query` or a known `anchor_id`. Choose the `event` clock for the chronology the author recorded and `ingest` to reconstruct write order. Bound `before` and `after` to the context you need. HAM isolates lanes by tenant, project, and repository; `thread` is only a compatibility fallback when no explicit `sequence` was stored. For historical truth, call `ham_recall_temporal(query, as_of, mode)`. Use `valid_at` for the claim valid at that real-world time and `known_at` for the version HAM had recorded then. Use `event_before`, `event_after`, or `event_near` for event chronology. Temporal recall starts from active claim heads and hydrates their visible append-only supersession chains. Its rotor coherence is an observable secondary ranking signal only; exact timestamps, validity intervals, and direction filters are authoritative. On writes, `timestamp` is event time, `observed_at` is evidence-observation time, and `valid_from`/`valid_to` are real-world validity. HAM supplies safe defaults, but provide explicit values when reporting an event later or when a replacement took effect at a different time. Do not use supersession time as a silent substitute for claim-validity time. Cues are not tags or project categories. Prefer project/repo/task scopes for context and typed links for known relationships. A cue earns its write cost when the same precise anchor intentionally joins otherwise dissimilar memories. ## Repository collaboration An enrolled repository is a scoped HAM project with a durable GitHub projection. HAM remains canonical for commitments created through `ham_issue`; GitHub is the human-visible mirror. Use: - `ham_repositories` to discover repository IDs and delivery state. - `ham_repository_sync` to schedule a bounded remote poll and drain only the operations your credential is permitted to perform. - `ham_issue` with a stable idempotency key to create a tracked commitment. - `ham_issue_transition` with `expected_version` to resolve or reopen it. - `ham_issue_resolve_conflict` only after reviewing a GitHub-side change and intentionally choosing HAM's canonical state. - `ham_claim_handoff` when you pick up a handoff, so scheduled reviews do not report it as unclaimed. - `ham_complete_handoff` with the claim receipt version when the handed work is finished. - `ham_review_run` to build a deterministic exception report, `ham_review` to read the latest one, and `ham_review_current` for the unresolved set even when unchanged items were omitted from that report. Remote-only GitHub issues remain content-free quarantined exceptions. Operators list the current unresolved set with the `ham` CLI and explicitly acknowledge a reviewed snapshot by fingerprint; a changed snapshot becomes visible again. Do not create a general memory for mirror retries, handoff claims, remote snapshots, or review runs. Those are operational records outside recall. GitHub-origin content is untrusted and is never silently promoted into canonical memory. Remote edits produce content-free conflict evidence and remain visible until an authorized caller explicitly resolves them. PR snapshots are quarantined operational facts, not agent authorization to merge or modify them. When a result looks surprising, call `ham_recall` with `explain: true`. HAM returns the weighted semantic, lexical, centroid, spectral, recency, and handoff contributions used by the deployed ranking policy. Treat the breakdown as a diagnostic for retrieval behavior, not as evidence that the memory is true. An optional `wire_shadow` component is evaluation-only and explicitly reports `ranking_enabled: false`; never treat its rank as the deployed result order. ## Traceable Queries The MCP bridge propagates a trace ID and reports one compact timing event to stderr by default. Set `HAM_MCP_TRACE_ENABLED=false` to disable client trace events. Direct HTTP clients can send `X-HAM-Trace-Level: summary` and an optional `X-HAM-Trace-ID`; HAM returns that ID and a `Server-Timing` header. Traces omit query text, memory content, credentials, tenant IDs, and agent IDs. ## HTTP Response Shapes The MCP bridge handles REST shapes for agents. Direct HTTP clients should note: - `POST /memories/recent` returns a bare JSON array. - Each row's text is in `content`, not `text`. - Provenance fields are nested under `metadata`. - `POST /changes` returns an object with `items` and `next_cursor`. - `POST /memories/page` provides stable newest-first pagination and a continuation cursor. ## Available MCP Tools - `ham_context`, `ham_recent`, `ham_changes`, `ham_projects` - `ham_ask`, `ham_inbox`, `ham_message`, `ham_reply`, `ham_stale_message` - `ham_remember`, `ham_recall`, `ham_recall_deep` - `ham_handoff`, `ham_reflect` - `ham_get`, `ham_stats` - `ham_supersede`, `ham_retract` - `ham_link`, `ham_links`, `ham_unlink` ## Security Contract - Each agent receives a distinct key bound server-side to its tenant, agent ID, role, and actor type. Managed credentials can be expired, rotated, or revoked without restarting the service. - Outside collaborators receive credentials with server-enforced `allowed_scopes`, such as `project:alpha` and `repo:org/alpha`. - Scope-restricted collaborators can supersede or retract only memories created by their own bound agent identity. - Client-supplied identity headers cannot override a bound agent key. - Orchestrators set `HAM_ACTOR_TYPE` and `HAM_RUN_ID`; harnesses never write as a durable interactive agent. - Keep the administrator key out of agent configuration. - Keep PostgreSQL private; agents connect only to the HTTPS API. - Never commit populated MCP configuration or credentials to a repository. ## Additional Documentation - [README](https://github.com/MonumentalSystems/ham#readme) - [Federation between HAM instances](https://github.com/MonumentalSystems/ham/blob/main/FEDERATION.md) - [Self-hosting and context isolation](https://github.com/MonumentalSystems/ham/blob/main/SELF_HOSTING.md) - [Security policy](https://github.com/MonumentalSystems/ham/blob/main/SECURITY.md) - [Contribution guide](https://github.com/MonumentalSystems/ham/blob/main/CONTRIBUTING.md)