Install
$ agentstack add mcp-yeomyeonggeori-blueclaw ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
blueclaw — a POSIX-isolated, multi-user agent host
[](https://github.com/yeomyeonggeori/blueclaw/actions/workflows/ci.yml) [](go.mod) [](LICENSE)
> Status: pre-alpha, under active development. The interfaces, the wire > grammar, the configuration keys and the database schema all still change > without notice, and there is no release, no versioning policy and no upgrade > path between commits. It is published so the design can be read and argued > with, not so it can be depended on. If you run it, pin a commit and expect to > read diffs.
A company runs one agent on one machine and everyone talks to it. To a harness that runs as whoever started it, the whole company is one Unix account: one home directory, one set of files, one view of every secret, and no record of which person authorized which side effect. Sales can read engineering's drafts because nothing on the machine knows they are different people.
blueclaw is the host that makes them different people, and POSIX is how. It is an open source, self-hosted Go daemon that runs an AI agent harness on behalf of whichever person asked, executes each requester's tool calls as their own unprivileged Linux user, holds side-effecting calls at an approval gate, and writes every step to a durable event ledger. It owns identity, isolation, task state, the tool catalog, and delivery.
blueclaw-cli is the terminal client above; the host is what it connects to.
The agent loop is a replaceable component behind a Go interface (agentcontract.Harness, one method). Five harnesses are selectable, one of them in this repository. Swapping it does not move the isolation boundary, because tool execution never leaves blueclaw.
What blueclaw is, and what it is not
| It is | It is not | |---|---| | a host process that runs an agent harness on other people's behalf | an agent, an agent loop, or a model | | a POSIX identity boundary between the people sharing one machine | a container runtime or a sandbox technology | | a durable task store with an append-only event ledger | a chat client | | an MCP client that mounts external tool servers into the catalog, and an MCP server that publishes the requester's catalog to an external harness | a general-purpose MCP server for arbitrary clients | | a Go binary you build from source and self-host | a hosted service or a packaged binary release |
Read the right-hand column literally. blueclaw separates requesters from each other, not the agent from the machine; a container does the latter, and the two compose.
blueclaw is the agent host inside InternKim, an on-premise AI automation appliance.
Why an agent host, not another agent
Agent harnesses are already abundant: Claude Code, Codex, opencode, Gemini CLI, and the loop bundled here. They all run as whoever started them. On a shared, multi-user machine that means one Unix account for every requester, no per-person file separation, and no record of which human authorized which side effect.
Self-hosted assistants have the same shape from the other direction. openclaw and the projects around it put a capable agent on your own machine, and that is the right answer for one person. Nothing stops a team pointing several people at one of them. They were simply not designed for it, so the second person who asks for something gets the first person's home directory, the first person's secrets, and a ledger that cannot say who authorized what. blueclaw starts from the assumption those projects do not make.
blueclaw takes the opposite split. The harness decides what to call. blueclaw decides who it runs as, whether it runs at all, and what is written down. A harness that executes tools inside its own process is not an acceptable integration, because it takes back the only thing the host exists to provide.
The mechanical claim is narrow and testable: tool execution runs as an unprivileged POSIX user derived from each requester's identity, and POSIX ownership and mode bits are the only access boundary. There is no executable allowlist, no denied command list, no denied path prefix, and no instruction anywhere in a prompt telling the model what it may not touch. A command the requester may not run is not refused by blueclaw; it fails at the kernel, the same way it would fail for that person at a shell.
That is an opinion, and it cuts both ways. Inside the requester's permissions the agent is left alone — it may install a package, walk the filesystem, run a build, try something and undo it, without asking a policy engine whether each step is on a list. Every such list is a second, worse copy of the permissions the kernel already enforces: it goes stale, it blocks work the person is entitled to do, and the model learns to route around it. Confining a process is a solved problem, and the solution is fifty years old.
So the boundary is drawn once, at identity, and it is absolute. What is left is judgment about effects that leave the machine — sending a message, publishing a site, changing a shared calendar — and that goes to a person at the approval gate.
How it works
- connector — a platform adapter; normalizes an inbound message.
- task run — a durable record of one unit of work.
- event ledger — the append-only events belonging to a task run.
- approval gate — holds a tool call until a human authorizes it.
- POSIX projection — maps policy objects to real Linux users and groups.
chat platform / HTTP ingress
|
v
blueclaw (Go daemon)
connectors · policy · task store · approvals · tool catalog · POSIX projection
|
+-- agentcontract.Harness --+-- .dependency/bluecollar (Go, in-process)
| +-- an ACP or CLI agent, started as the requester
|
+-- tool execution --> blueclaw-posix-helper --> each requester's UID/GID/groups
Intake: connectors normalize a message
Four connector adapters are registered at boot — mattermost, slack, signal, and api — plus buzz when connectors.buzz.enabled is set (internal/app/application.go). Each turns a platform-specific payload into the same normalized conversation turn. The api connector needs no chat platform at all and is the way to drive blueclaw from curl or a test.
Intake resolves the sender to a person in the policy document. That resolved person, not the daemon account, is the identity every later step runs under.
Task runs and the event ledger
A task run is a row in the task store with one of nine statuses (.dependency/bluecollar/taskstate/task_type.go): planned, running, waiting_user_input, waiting_approval, blocked, interrupted, completed, failed, cancelled.
Every step appends an event through TaskEventService.AppendTaskEvent (.dependency/bluecollar/taskstate/task_event_service.go). Event names follow a fixed wire grammar — tool..requested, tool..result, approval.pending_call, approval.executed, agent.task_launched, and, for a tool an external harness ran outside the catalog, harness.tool_permitted and harness.tool_refused. A reader can reconstruct what happened without access to the harness's internal types.
Approval gates
An approval gate pauses a task run before a side-effecting tool call executes and records approval.pending_call with the exact call (internal/approvalgate, taskstate.TaskRunService.PauseTaskRun). Because the held call is persisted, approval survives a daemon restart and does not block a live request.
How the approved call then runs depends on which harness held it. The bundled loop replays the recorded call verbatim (.dependency/bluecollar/approval_gate.go). Every other harness is told in its next prompt that the approval arrived and asked to issue that exact call again, so the replay depends on the agent reproducing its own arguments. Levelling every harness up to a verbatim replay needs the result of a host-executed call to reach the agent, and the only channel for that today is the loop's own in-process observation format, so it waits for the ledger to cross the harness boundary.
Which calls are gated comes from descriptor metadata, not from the tool's name. toolcontract carries an ApprovalScope and one of 14 SideEffectClass values per tool (.dependency/bluecollar/toolcontract/registry.go), from none and read through workspace_write, external_send, site_publish, and destructive.
The gate belongs to the host, not to a harness. internal/approvalgate holds the call and internal/mcpserver consults it before invoking anything from the catalog, so every harness meets the same gate on the same calls.
Sending a message, changing a calendar, publishing a site — every outward or irreversible effect exists only as a catalog tool, and an external agent has no other route to one. internal/acpharness also refuses ACP's own filesystem and terminal methods, which pushes an agent's file and shell work back onto the catalog rather than letting it run beside the gate.
What remains outside is the tools an agent runs inside its own process: goose's shell, Claude Code's editor. Those are answered yes. The boundary there is POSIX — the agent runs as the requester's unprivileged user, and a shell call it makes itself can do no more than one made through terminal_run. The answer is recorded: harness.tool_permitted and harness.tool_refused go to the event ledger, so reading a task afterwards shows the calls the catalog never saw.
One asymmetry is not ours to fix. ACP has a permission channel and a command line does not, so a CLI harness offers nothing to record.
POSIX identity projection
Every person in the policy document projects to a real Linux user and every circle to a real group (internal/security/posix_identity.go):
| Policy object | Linux object | Symbol | |---|---|---| | person | bc_person_ user with a primary group of the same name | LinuxPersonUserName | | circle | bc_circle_ group | LinuxCircleGroupName | | everyone | bc_shared supplementary group | posixSharedGroupName | | service internals | blueclaw user | blueclawServiceUserName |
Names are lowercased, reduced to [a-z0-9_-], and capped at 31 characters. A lossy or truncated normalization gets a hash suffix, so two people cannot collide onto one account (shortenedLinuxName).
POSIXStateForPolicy compiles the policy into the users, groups, and directory modes the daemon applies at every boot:
| Path | Owner:group | Mode | |---|---|---| | /private/people/ (and tmp/, artifacts/) | the person | 0700 | | /circles/ | blueclaw:bc_circle_ | 2770 | | /shared | blueclaw:bc_shared | 2755 | | /shared/public, /shared/cache/** | blueclaw:bc_shared | 2775 | | /private, /private/people, /circles | blueclaw:blueclaw | 0711 |
/.blueclaw — the daemon's own state, logs, configuration, and identity map — appears in no projected directory entry, so it is never chowned or chgrped to a task user and stays owned by the service account.
UIDs and GIDs are allocated from 100000 upward through a persisted allocation table (cmd/blueclaw-posix-helper/main.go), so a person keeps the same numeric identity across restarts and reprovisions and existing file ownership does not drift.
Quickstart
There is no packaged install path in this repository: no Makefile, no Dockerfile, no service unit, no release binaries. Running blueclaw means building from source. The appliance tooling that provisions, packages, and deploys it lives in a separate private repository.
Requirements: Go 1.26, Bun 1.3, Postgres, and one OpenAI-compatible model endpoint — Ollama, vLLM, LM Studio, OpenRouter, or anything else speaking that API.
1. Start llmd, the model sidecar. It holds the provider credentials and runs beside the daemon.
cd llmd
printf 'a-local-secret' > /tmp/llmd-auth
BLUECLAW_LLMD_AUTH_KEY_PATH=/tmp/llmd-auth \
BLUECLAW_LLMD_SOCKET_PATH=/tmp/llmd.sock \
BLUECLAW_LLMD_LLAMA_BASE_URL=http://127.0.0.1:11434/v1 \
BLUECLAW_LLMD_LLAMA_MODEL=your-model \
BLUECLAW_LLMD_LLAMA_STRUCTURED_OUTPUTS_ENABLED=true \
BLUECLAW_LLMD_LOCAL_ONLY=true \
bun run src/main.ts
LLAMA_BASE_URL points at any OpenAI-compatible server; the name is historical. http://127.0.0.1:11434/v1 is Ollama. For a hosted provider, set OPENROUTER_API_KEY and drop the local variables. llmd/README.md lists the credential setting.
Treat a local model as a development convenience. The runtime asks for structured output natively and falls back to a forced tool call when the server rejects that; Ollama treats the forced choice as a hint, so a model may answer in prose and fail the turn. Small models also struggle with the larger runtime schemas.
2. Start the daemon. Copy config/runtime.standalone.example.json, set your Postgres connection string and the llmd socket and key paths, then:
go run ./cmd/blueclaw --runtime runtime.json --policy config/policy.example.json
curl -s localhost:8081/admin/api/health | jq '.status, .protocolIdentity.passed'
cmd/blueclaw takes exactly two flags, --runtime and --policy; everything else is configuration. The 29 migrations under migrations/ are applied in order at boot.
A standalone deployment reports capabilityd: not_configured and checks only llmd. There is no capability service, so the calendar, task, mail, and site operations an appliance supplies are simply absent. The agent loop, skills, the terminal, and files work.
3. Enable per-person POSIX isolation. Until this step every requester shares the daemon's account; this is the step that makes blueclaw multi-user. The projection is applied only when terminal.posixHelperPath is set. Build and install the setuid helper, then point the configuration at it:
go build -o /usr/local/bin/blueclaw-posix-helper ./cmd/blueclaw-posix-helper
sudo chown root:root /usr/local/bin/blueclaw-posix-helper
sudo chmod 4755 /usr/local/bin/blueclaw-posix-helper
The daemon then synchronizes users, groups, and directory modes from the policy document at every boot (internal/app/application.go).
4. Give it work, as two different people. Address two people from your policy by email through the api connector:
for sender in ada@example.com grace@example.com; do
curl -s -X POST localhost:8081/connectors/api/events -H 'content-type: application/json' \
-d "{\"conversationID\":\"dm:api:$sender\",\"messageID\":\"m1\",\"senderID\":\"$sender\",
\"replyTargetID\":\"dm:api:$sender\",\"prompt\":\"Write your name to a file in your home directory.\"}"
done
curl -s 'localhost:8081/agent/api/replies?conversationID=dm:api:ada@example.com'
The two runs execute as different Linux users with different 0700 home directories. Neither can read the other's file, and the ledger records which of them authorized which side effect. That is the whole claim, and it takes about thirty seconds to watch.
To watch a whole scenario instead, the lab runner drives the agent loop and writes every request, response, tool call, and artifact to a directory:
go run ./cmd/blueclaw-lab virtual-session --scenario presentation \
--artifact-dir .artifacts/blueclaw-e2e --live-llm --llm-unix-socket /tmp/llmd.sock
Live runs spend money, so they are never enabled by configuration alone. The explicit --live-llm flag or BLUECLAW_E2E_LIVE=1 is required (cmd/blueclaw-lab/main.go). Scenario names resolve through e2e.BuiltinScenario; the scenarios are defined in internal/e2e/scenarios.go, and --scenario-file loads one from JSON instead.
Terminal interface
cmd/blueclaw-cli is how you watch and answer a running daemon from a terminal. It talks to the admin API over HTTP, so it runs wherever you can reach the daemon.
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [yeomyeonggeori](https://github.com/yeomyeonggeori)
- **Source:** [yeomyeonggeori/blueclaw](https://github.com/yeomyeonggeori/blueclaw)
- **License:** Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.