---
title: Coding agents
description: Govern Claude Code, Codex and Kiro on developer machines with
  Titan's titand daemon, managed hooks and signed local tool rules, and what
  this does not cover.
url: https://hexelstudio.com/docs/titan/coding-agents
---

Titan governs coding agents that run on your developers' Linux machines (including WSL2): **Claude Code**, **Codex CLI** and **Kiro CLI**. A small daemon, `titand`, binds each machine to your Titan deployment and answers the agent's hooks before each tool call. Developers start their agent the usual way.

During the private preview, Hexel Studio provides `titand` and your organization's attach descriptor (the file or URL that names your Titan deployment).

## What Titan checks on the machine

Before each tool call, the coding agent's hook asks `titand`. A call is allowed only when all of these hold:

1. The machine is enrolled and has a live Titan session.
2. The session is not suspended, revoked, quarantined or killed (see [Kill switch](https://hexelstudio.com/docs/titan/kill-switch)).
3. `titand` has heard from Titan recently. Offline, it keeps deciding for up to 15 minutes by default (at most 4 hours), then denies.
4. For Claude Code and Codex, the call passes your [signed local tool rules](#signed-local-tool-rules), if you publish any.

If `titand` isn't running, the agent's tool calls are denied.

Titan's own tools, offered to the agent through the Titan MCP server, are decided by Titan centrally like any other governed action. From a developer machine, only read-only capabilities are offered.

## Install

| Agent | Install | Managed (recommended) |
| --- | --- | --- |
| Claude Code | `titand claude install --org <descriptor>` | `sudo titand claude install-managed` |
| Codex CLI | `titand codex install --org <descriptor>` | `sudo titand codex install-managed` |
| Kiro CLI | `titand attach --org <descriptor>` | — |

Each install enrolls the machine for that agent with its own key, puts a `titand` shim ahead of the real binary on `PATH` (recording the real binary's digest), writes the agent's hook configuration, and registers the Titan MCP server. `titand status` shows the deployment the machine is bound to.

### Managed hooks

Use managed hooks. They are the only mode in which a developer can't simply switch the hooks off.

- **Claude Code:** `install-managed` writes a drop-in under `/etc/claude-code/managed-settings.d/` with `allowManagedHooksOnly`. Your organization's own `managed-settings.json` isn't rewritten. If you deliver Claude Code settings from a server or MDM, those take precedence over the files, so add the same hooks there.
- **Codex CLI:** `install-managed` writes the hooks into `/etc/codex/requirements.toml` with `allow_managed_hooks_only = true`.
- **User-level hooks** (`install` without the managed step) live in the developer's own settings, which they can edit or disable. Titan labels this mode as easy to bypass.

To remove the integration, run `titand claude uninstall` or `titand codex uninstall` (and `sudo titand <agent> uninstall-managed` for managed hooks).

## Signed local tool rules

Local tool rules let you deny specific built-in tool calls of Claude Code and Codex, such as `rm -rf` or reading `~/.ssh`. Titan signs them, and `titand` checks the signature and evaluates them on the machine after the checks above. A rule can only turn an allowed call into a denied one. It never overrides a kill or a suspension.

### Write the rules

`PUT /v1/titan/management/deployments/{id}/local-tool-rules` replaces the whole rule set (permission `titan:policy:publish`; reading needs `titan:policy:read`):

```bash
curl -X PUT https://api.hexelstudio.com/v1/titan/management/deployments/$TITAN_DEPLOYMENT_ID/local-tool-rules \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "default_effect": "allow",
    "rules": [
      { "id": "no-rm-rf", "tool_class": "shell", "executable": "rm", "arg_tokens": ["-rf"],
        "effect": "deny_with_message", "message": "Deleting recursively is not allowed here." },
      { "id": "no-force-push", "tool_class": "shell", "executable": "git", "arg_tokens": ["push", "--force"], "effect": "deny" },
      { "id": "no-ssh-keys", "tool_class": "file_read", "path_prefix": { "prefix": "~/.ssh", "scope": "outside_workspace" }, "effect": "deny" }
    ]
  }'
```

| Field | Values |
| --- | --- |
| `default_effect` | `allow` or `deny`, for a call no rule matches. Required. |
| `tool_class` | `shell`, `file_write`, `file_read`, `network_fetch` or `mcp` |
| `executable` | `shell` only: the exact program name, such as `git` |
| `arg_tokens` | `shell` only: exact arguments that must all be present in the same command |
| `path_prefix` | `file_read` and `file_write` only: a `prefix` with `scope` `inside_workspace` (relative path) or `outside_workspace` (absolute or `~/` path) |
| `effect` | `allow`, `deny`, or `deny_with_message` with a `message` the agent sees |

A rule matches when the tool class is the same and every matcher it has matches. There are no regular expressions over the raw command text, because quoting and substitution would defeat them. An invalid set is refused with `400 LOCAL_TOOL_RULES_INVALID`. At most 256 rules.

### Deliver them to machines

1. After the `PUT`, read the rules with `GET` until the response has a `bundle`. Its `verification_keys` are the keys machines must trust.
2. Add those keys to your attach descriptor as `local_tool_rules_keys`, and run the agent's `install` again on each machine.

From then on, `titand` fetches new versions within about a minute after Titan signs them. A signed bundle lasts one day and Titan renews it automatically. A machine that pins keys but has no valid bundle, or whose bundle has expired, denies every built-in tool call.

The Agent Ledger records each rule decision with only the rule id, the bundle generation and the decision. It doesn't record the command, the path or the arguments.

## What this does not cover

Coding-agent governance works through the agents' hooks. It is a guardrail, not endpoint protection.

- It doesn't see anything a developer or a process does outside the agent: their own shell, editor, clipboard, network or existing credentials.
- An agent started without its hooks isn't governed: the real binary run by its full path, another profile or configuration without the Titan hooks, or user-level hooks the developer turned off. Codex's `--dangerously-bypass-hook-trust` is another such path.
- Codex's hosted tools, such as web search, run outside hooks and are never seen by Titan.
- On WSL, `/etc/claude-code` can be writable by the user, so managed hooks there don't resist a user who can write to it.
- Local tool rules can't rewrite a call or ask a person to approve it; they only allow or deny. Approvals happen through Titan's own tools, never inside a hook.

What makes going around Titan low-value is that governed tools hold no credentials on the machine: an agent without Titan has nothing to act with on the systems Titan governs.
