{"id":50639405,"url":"https://github.com/martianoff/gala-acp","last_synced_at":"2026-06-07T07:02:00.682Z","repository":{"id":363024189,"uuid":"1261687618","full_name":"martianoff/gala-acp","owner":"martianoff","description":"Transport-neutral Agent Communication Protocol for GALA: content-hash message identity, idempotent dedup, a delivery/liveness FSM, and a generic agent-run contract — with a Claude backend.","archived":false,"fork":false,"pushed_at":"2026-06-07T03:08:40.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T05:06:32.386Z","etag":null,"topics":["acp","agent-communication-protocol","agent-orchestration","claude","functional-programming","gala","immutable","llm-agents"],"latest_commit_sha":null,"homepage":null,"language":"Starlark","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/martianoff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T02:54:52.000Z","updated_at":"2026-06-07T03:08:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/martianoff/gala-acp","commit_stats":null,"previous_names":["martianoff/gala-acp"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/martianoff/gala-acp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martianoff%2Fgala-acp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martianoff%2Fgala-acp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martianoff%2Fgala-acp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martianoff%2Fgala-acp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martianoff","download_url":"https://codeload.github.com/martianoff/gala-acp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martianoff%2Fgala-acp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34011812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acp","agent-communication-protocol","agent-orchestration","claude","functional-programming","gala","immutable","llm-agents"],"created_at":"2026-06-07T07:01:57.328Z","updated_at":"2026-06-07T07:02:00.677Z","avatar_url":"https://github.com/martianoff.png","language":"Starlark","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gala-acp — Agent Communication Protocol\n\nA standalone, transport-neutral [GALA](https://github.com/martianoff) library for\nbuilding **reliable** agent orchestrators. It is the shared protocol kernel\nextracted from [`gala_team`](https://github.com/martianoff/gala_team)'s\n`app/protocol` and designed to fit\n[`gala-assimilator`](https://github.com/martianoff/gala-assimilator)'s engine\nACP — one library, reused by both.\n\nThe **`acp` kernel** is **pure data + pure functions**: no subprocess, no\nfilesystem, no UI, no clock. The optional **`agent` package** is the impure\nedge — a transport-neutral agent port plus a `claude` CLI backend — kept in its\nown package so the kernel stays pure and dependency-light.\n\n## What's inside\n\n### `acp` — the pure protocol kernel\n\n| File | What it gives you |\n|------|-------------------|\n| `envelope.gala` | `Envelope` — the on-the-wire message with **content-hash identity**. Re-deriving an envelope from the same inputs yields the same `Id`; idempotency, dedup, and the stale-redelivery defence all fall out of that one fact. |\n| `ledger.gala` | `Ledger` + `DedupById` — the durable dedup gate keyed on that identity. Admit each `Id` exactly once; re-emitted chunks / replays / redeliveries collapse. |\n| `delivery.gala` | The delivery / ack / retry / nudge **liveness FSM** (`DeliveryState`, `DeliveryAction`, `Tick`, `OnChunk`, `OnTerminal`, `AggregateNudges`). A pure function of (state, event, clock, policy). |\n| `run.gala` | The generic **agent-run contract**: `AgentRunner[A, R, C]` port, `RunTranscript` (stream-as-data), `RunOutcome` (result / clarification / aborted terminus), `ProgressEvent`. |\n\n### `agent` — the transport port + Claude backend (`github.com/martianoff/gala-acp/agent`)\n\nThe impure edge: where \"an agent\" stops being pure data and becomes a live\nconversation. Import this only if you need to actually *run* an agent.\n\n| File | What it gives you |\n|------|-------------------|\n| `agent.gala` | The transport-neutral port: `AgentTransport` (open a session), `AgentSession` (`Send`/`EndTurn`/`NextEvent`/`Close`), and the `AgentEvent` / `AgentInput` / `AgentSpec` value types. Swap the backend without touching the orchestrator. |\n| `claude_transport.gala` | `ClaudeProcessTransport` — the default backend: a local `claude` CLI subprocess over stream-json (prompt on stdin, `--input-format`/`--output-format stream-json`), with the IO ↔ `AgentEvent` mapping and the transport-auth-error gate. |\n| `claude_stream_json.gala` | The claude-code stream-json classifiers/extractors (envelope shape, tool_result blocks, stale-resume detection). |\n| `session_id.gala` | `NewSessionId` — RFC 4122 v4 UUIDs for `--session-id` / `--resume`, so parallel member subprocesses don't race on claude's \"most recent in cwd\" semantics. |\n\n`AgentSpec` carries only what a transport needs (`Model`, `Workspace`,\n`SessionId`, `IsNewSession`, `DangerouslySkipPermissions`) — no consumer-\nspecific member type. The `TraceClaudeLine` diagnostic hook (`trace.gala`) is a\ndocumented no-op: tracing to a debug sink is a consumer concern, so the package\nships no file IO.\n\n### Vocabulary is the consumer's\n\nThe kernel carries **no domain message taxonomy**. `Envelope.Kind` is an opaque\nlowercase string tag, so one app can speak `dispatch / finished / consult`\nwhile another speaks `task_assignment / result / verdict` — both ride the same\nenvelope, the same dedup `Ledger`, the same delivery FSM. A consumer that wants\nan exhaustive sealed kind keeps its own sealed type and projects it to the tag\nat the boundary (the tag is all the kernel needs for identity and routing).\n\nThe run contract (`run.gala`) is generic over the consumer's payload types\n(`A` = assignment, `R` = result, `C` = clarification) so each application plugs\nin its own shapes while sharing the port, the transcript, and the terminus\ninvariant.\n\n## Using it\n\n### Bazel (bzlmod)\n\n```starlark\n# MODULE.bazel\nbazel_dep(name = \"gala_acp\", version = \"0.1.0\")\n\n# Until gala-acp is published to a registry, point at a local checkout:\nlocal_path_override(module_name = \"gala_acp\", path = \"../gala-acp\")\n```\n\nA cross-module GALA library must sit on the transpiler's search path, so wire\nit through **`gala_deps`**, not `deps`:\n\n```starlark\ngala_library(\n    name = \"...\",\n    srcs = [...],\n    gala_deps = [\"@gala_acp//:gala_acp\"],\n    deps = [...],\n)\n```\n\nIf you use the gazelle extension, add a resolve directive so it keeps the dep in\n`gala_deps`:\n\n```\n# gazelle:resolve gala github.com/martianoff/gala-acp @gala_acp//:gala_acp\n```\n\n### Pure GALA (`gala build` / `gala test`)\n\n```\n# gala.mod\nrequire github.com/martianoff/gala-acp v0.1.0\n```\n\nThen `import \"github.com/martianoff/gala-acp\"` and reference `acp.Envelope`,\n`acp.Tick`, `acp.AgentRunner`, etc.\n\n## Build \u0026 test\n\n```sh\nbazel build //...\nbazel test  //...\n```\n\n## A taste\n\n```gala\nimport . \"github.com/martianoff/gala-acp\"\n\n// Reliable messaging: identity is a content hash, dedup is a one-liner.\nval m       = NewEnvelope(\"_lead\", \"Felix\", \"dispatch\", \"build the parser\", 0)\nval (l2, _) = EmptyLedger().Admit(m)   // admits once; a re-decoded duplicate is rejected\n\n// Liveness: one total FSM decides retry / nudge / abandon.\nval (next, action) = Tick(Sent(AtNanos = 0, Attempt = 1), m, nowNanos, DefaultDeliveryPolicy())\n\n// The run contract: a Submit is a pure TaskAssignment -\u003e RunTranscript value.\nval runner = StaticRunner[string, string, string](\n    RunTranscript[string, string](\n        Steps = ArrayOf[RunStep](ProgressStep(\"task-1\", \"reading\", \"reading source\")),\n        Final = OutcomeResult[string, string](Value = \"// translation\"),\n    ),\n    Cancelled(),\n)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartianoff%2Fgala-acp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartianoff%2Fgala-acp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartianoff%2Fgala-acp/lists"}