# hilos-agent

Run **your own** coding agent — Claude Code, Codex, Cursor, opencode,
Antigravity, Hermes, or any command — as
an autonomous teammate inside a [hilos](https://hilos.sh) channel.

It connects to hilos over MCP, watches for `@mentions` of your agent in a
git-linked channel (including thread replies) and for **every message in a DM
with your agent — no tag needed there**, runs your coding agent in a
**local** checkout, and — by default — **opens a PR for review**. The checkout
and your coding-provider/git credentials stay on your machine. Changes go to the
configured Git remote; hilos receives bounded plans, progress, reports, and—when
the pre-push gate is enabled—the proposal diff.

```
hilos channel  ──MCP/HTTPS──▶  hilos-agent (your laptop)
  human: "@scout fix the navbar overflow"
  agent: branches, runs your coding CLI, commits + pushes, opens a PR
  agent: posts a report card with the PR link
  human: Approve  ▶  hilos merges the PR
         Reject   ▶  hilos closes the PR
         Changes  ▶  agent re-works with your note
```

Prefer **approve-before-push**? Set `"gate": true` — the agent posts a bounded
proposed diff to hilos as a card, then pushes the change to the Git remote only
after you Approve.

## Quick start

Run `npx hilos-agent@latest doctor` first if you already have a saved config.
For a new connection, use `npx hilos-agent@latest doctor --join-stdin` with the
private join code and the same command settings you will use to run the daemon.
Read the JSON and resolve each failed check before starting it.

In hilos: open your agent's profile → **Connect agent** → **Run in channel**. Copy the
terminal command and run it from inside your repo's folder. It waits at a hidden
prompt; copy the private join code from Hilos and paste it there. The daemon
matches the repo by its git remote, so no config is needed, and the reusable
credential never enters shell history or the process list:

```sh
cd ~/code/your-repo
npx hilos-agent@latest doctor --join-stdin  # check setup with the private join code
npx hilos-agent@latest --join-stdin  # then paste the private join code when asked
```

Previously copied `--join <blob>` commands remain compatible. New commands use
stdin because the blob contains the agent token and should not live in argv.

The daemon prints `log: <path>` when it starts. Its local diagnostic log lives
at `~/.hilos/logs/<handle>.log`, with one previous file at `<handle>.log.1`.
Each file is capped at 2 MB, private to your user, and redacted for
credential-shaped text. Before identity discovery, the name is `agent-<pid>`;
those startup lines move to the handle's log after connection. The final
`exit:` line records a signal, authentication stop, fatal error with its stack,
or normal shutdown. A forced kill or power loss cannot write an exit line.
An IDE agent can read these files when diagnosing a daemon that went quiet.

After three minutes without a daemon heartbeat, hilos posts one notice in the
last room that mentioned the agent (falling back to its latest run's room).
The notice names who can restart it with the same join code. For hilos-hosted
agents, it also explains that hosted mentions use workspace credits until the
daemon returns. The owner gets the existing quick-connect card; everyone in
the room can read the notice.

Running from elsewhere, or want to map several repos explicitly? Save this as
`~/.hilos/agent.json` (or `./hilos-agent.json`). The file is strict JSON, so it
cannot contain comments:

```json
{
  "url": "https://hilos.sh/api/mcp",
  "token": "mgo_…",
  "repos": { "your-org/your-repo": "/Users/you/code/your-repo" },
  "codingCmd": "claude -p --permission-mode acceptEdits",
  "codingModel": "",
  "chatCmd": "",
  "webSearch": true,
  "defaultBranch": "main",
  "gate": false,
  "heartbeatMs": 180000,
  "chatTimeoutMs": 90000,
  "longPollMs": 20000,
  "catchupMs": 86400000
}
```

`codingCmd` above is the safe default; it can also be `codex exec`,
`cursor-agent -p --output-format text --trust`, `opencode run`, `agy -p`, or a
custom command. `codingModel` accepts the Codex tiers `most-capable`, `balanced`,
or `fastest`; empty uses the tool's default. Empty `chatCmd` derives a fast chat
command from `codingCmd`. `webSearch: false` disables hilos's web-search
enablement, and `gate: true` switches to approve-before-push. `heartbeatMs: 0`
disables the heartbeat (minimum nonzero value 15 seconds); `longPollMs: 0` uses
plain five-second polling; `catchupMs: 0` restarts at now instead of replaying
the default 24-hour window.

**Staying responsive.** Every code task posts an **instant acknowledgement**
(under a second), and — if your server exposes `edit_message` and a fast chat
command can be resolved (explicit `chatCmd` or one derived from `codingCmd`) —
a quick **plan** ("On it — I'll do X, then open a PR") edits into it. On a
run longer than `heartbeatMs` (default 3 min; env `HILOS_HEARTBEAT_MS`, `0`
disables, clamped to ≥15s) the agent posts **one progress reply** in the thread
then edits it in place with elapsed time + the CLI's latest line — so the channel
shows it's alive without thread spam. When the run ends, that message is retired
to a short "done" line. A run that **times out or errors** says so honestly (with
a stderr tail) instead of claiming "no changes". Chat replies use the faster
`chatCmd` (when unset, derived from `codingCmd`'s tool — a Claude daemon chats
with Haiku, a Codex daemon with `codex exec`, and so on) bounded by
`chatTimeoutMs`. The chat-vs-code pass only classifies; the separate chat
responder keeps the CLI's normal tools. Public web is on by default and stays
native to the selected CLI: Hilos pre-approves Claude Code's read-only
`WebSearch`/`WebFetch`, enables Codex search, turns on OpenCode's official Exa
search switch, preserves Hermes's full web-capable coding toolset, and keeps
Cursor and Antigravity's built-ins. Generated chat replies use Cursor `ask`
with safe auto-review, OpenCode
`plan`, Antigravity `plan`, Codex's read-only sandbox, or Hermes `safe,web`
where available; coding runs keep their normal tool/approval policy. Run
`hilos-agent web doctor` to inspect the configured contract. Set
`"webSearch": false`, `HILOS_WEB_SEARCH=0`, or `--no-web-search` to stop Hilos
from enabling or requesting web use; the CLI's own global/project tool policy
still applies. Custom commands retain their own tools without guessed flags.
The responsive surface needs a hilos server new enough to expose
`edit_message`; older servers just skip the live edits.

```sh
hilos-agent          # watch every channel the agent is in
hilos-agent --channel <id>   # scope to one channel
```

## WebMCP site tools

The local daemon can give its coding and chat agents a narrow bridge to
third-party WebMCP sites. It is off until you name exact origins and exact read
tools in the machine's config:

```json
{
  "webMcp": {
    "origins": {
      "https://docs.example.com": {
        "readTools": ["search_docs", "read_reference"]
      }
    }
  }
}
```

The site does not authorize itself: `readOnlyHint` is informational, while this
person-owned list decides what may run. Site descriptions are omitted, schema
prose is stripped, results are bounded and labeled untrusted, and cookies stay
inside a separate browser profile. The optional browser bridge needs Node.js 24
or newer. On Node.js 20 or 22 WebMCP stays unavailable, while the rest of the
daemon keeps working regardless of whether that optional package was omitted by
the installer. Run `hilos-agent webmcp doctor` after upgrading Node.js and
reinstalling the package.

```sh
hilos-agent webmcp doctor
hilos-agent webmcp login https://docs.example.com  # person signs in in the opened browser
hilos-agent webmcp open https://docs.example.com/reference
hilos-agent webmcp tools
hilos-agent webmcp call search_docs '{"query":"WebMCP"}'
hilos-agent webmcp close
```

The daemon adds this capability and its citation rules to agent prompts only
when the config is valid. Unlisted tools — including writes — are refused with
`human_approval_required`; there is no approval flag the agent can set. WebMCP
can never approve or merge hilos work. This wrapper is a policy boundary for
the bridge, not a sandbox around the coding CLI, which still has the machine
access its operator granted. See the complete contract in
[WebMCP in hilos](https://hilos.sh/docs/webmcp).

## How it works

- **Trigger** — an `@mention` of your agent in a channel that's linked to a repo,
  or any message in a DM with your agent (a DM is the address — no tag needed;
  there, and only there, the agent may also answer with an emoji reaction or
  stay quiet when a message truly needs nothing).
  Mentions are picked up by polling; on servers that expose `get_wake_channel`,
  a realtime doorbell (a content-free broadcast on every new message) wakes the
  poll instantly, so pickup takes about a second instead of a poll interval
  (needs Node >= 22 for the built-in WebSocket; otherwise it just keeps polling).
- **Chat or code?** — the agent reads the conversation and decides with the model
  (via `chatCmd`), not a keyword list: a question/greeting/"let's just discuss" →
  a chat reply; anything asking for a change — including "just code it", "finish
  it", "approved", or "go for it" after a request, in any language → a code run.
- **Repo resolution** — the channel's linked repo is mapped to a local path via
  `repos`. No mapping → the agent says so and stops.
- **Run** — it temporarily stashes a dirty checkout, branches off
  `defaultBranch`, runs `codingCmd` with the task, stages the result, and attempts
  to restore the person's pre-existing work on every exit path. If `stash pop`
  conflicts, the stash stays intact and the room gets the recovery command.
- **Continue the thread's PR** — when the mention lands in a thread hilos says is
  about a pull request, the daemon works on *that* PR instead of opening a second
  one: it fetches the PR's head branch, commits there, and the same PR updates.
  It confirms with `gh` that the PR is still open first — a merged, closed, or
  fork PR gets a fresh branch, and the run says so.
- **Merge / close on request** — "merge it" from a workspace owner or admin in a
  PR thread is executed, not described. The daemon relays the request to hilos
  with the id of the message that asked; hilos verifies the person's role and
  that their message really asks for it, then acts with the workspace's GitHub
  App. If GitHub reports a same-repository merge conflict, the daemon keeps the
  same turn alive: it fetches the base branch, starts a real two-parent merge on
  the existing PR branch, names the conflicted files to the coding agent,
  verifies that no unmerged entries or conflict markers remain, and pushes the
  repaired head for fresh human review. It never opens a replacement PR or
  silently merges after repair. Fork PRs stop with an explicit writable-branch
  boundary. The daemon never merges on its own judgment and holds no merge
  rights. With `gate:true`, this existing-branch repair still pushes so the PR
  can return for fresh review. It is the only approve-before-push exception;
  the repaired head remains unmerged and needs a new approval.
- **Open a PR** (default) — it commits, pushes with *your* `git`/`gh`, opens a PR,
  and posts a report card with the link. Review on the card: **Approve** merges,
  **Reject** closes, **Request changes** re-works.
- **Recover an over-eager coding CLI** — if the child commits or switches
  branches despite the edit-only prompt, the daemon pushes that HEAD under the
  task branch it owns. It never asks GitHub to open the default branch against
  itself, and a rejected PR creation includes GitHub's actual error in the
  report.
- **Approve-before-push** (`gate:true`) — instead, it posts the staged diff as a
  card and polls for your decision; **Approve** pushes + opens the PR, **Reject**
  discards the branch, **Request changes** re-runs with your note (bounded rounds).

## Local folders (no repo required)

A channel doesn't need a linked GitHub repo to get coding work done. Map a channel
to a plain **local folder** and the agent works in it **directly** — it edits the
files in place (no branch, no commit, no PR), then posts a report of what changed.
It's your own machine, so this is the same trust as running the CLI yourself.

```json
{
  "folders": { "<channelId>": "/Users/you/notes-site" }
}
```

- **Trigger** — an `@mention` in a channel with **no linked repo** but a `folders`
  mapping. The same LLM router decides chat vs. code; a coding ask runs in the
  folder.
- **Git folders** — if the folder is a git repo, the agent snapshots `git status`
  before/after and reports the exact files it created/changed/removed plus a
  `git diff --stat`. It **never** touches your index, branches, pushes, or runs
  `gh`. On the report card: **Approve** keeps the changes (they're already live),
  **Request changes** re-runs in place with your note (bounded by `maxRounds`),
  **Reject** reverts *only what this run changed* (`git checkout` the files it
  modified, delete the files it created) — your pre-existing local edits are left
  untouched.
- **Non-git folders** — it still runs, but says up front it can't show a file-level
  diff or auto-undo; a reject asks you to revert by hand.
- A **linked repo always wins** — the folder map is only consulted when the channel
  has no repo link.
- **Folder link registration** — on startup the daemon registers each `folders`
  mapping with hilos (over the `link_folder` MCP tool) so the channel shows a
  folder chip — the folder's name, its full path, and which machine it lives on —
  without any manual step. It's best-effort and capability-gated: older servers
  that don't expose `link_folder` are skipped silently, and a failed registration
  only logs a line, never blocking the daemon. Registration happens once at
  startup, so a `folders` entry added while the daemon is running needs a restart
  to appear.

### Deploy the folder with your own hosting CLI

Add an optional per-channel deploy target next to `folders`:

```json
{
  "folders": { "<channelId>": "/Users/you/notes-site" },
  "deploy": { "<channelId>": { "provider": "vercel", "prod": false } }
}
```

`prod:false` means a preview deployment; `prod:true` means production. If the
setting is absent, the daemon detects `.vercel/` / `vercel.json` or `.netlify/`
/ `netlify.toml`; with no marker, deploy stays off. Install and sign in to the
matching CLI yourself (`vercel login` or `netlify login`). hilos stores no host
credential and never deploys silently: ask explicitly to put the folder live,
or use the report card's clearly labeled deploy action. The live URL comes back
on the same report card. CLI output is secret-redacted, the child receives no
`HILOS_*` variables, and failures remain caveats rather than false successes.

## Embedding the daemon

`run(cfg, opts)` is the poll loop, and it's embeddable. Beyond `handler`/`log` it
accepts:

```js
import { run } from "hilos-agent/src/run.mjs";

const controller = new AbortController();
await run(cfg, {
  signal: controller.signal,   // abort → interrupts the poll sleep, cancels the
                               //         active job, and returns cleanly
  onEvent: (e) => {            // lifecycle events for a host UI (wrapped in
    // e.type: "status" | "task-start" | "task-done" | "task-error"
    console.log(e);            //   try/catch — a bad listener can't crash the loop)
  },
});
// later: controller.abort();  // run() resolves once the active job tears down
```

Event shapes: `{ type: "status", text }`, `{ type: "task-start", channelId,
messageId, text }`, `{ type: "task-done", channelId, status }`, and
`{ type: "task-error", channelId, error }`. Both options are optional and fully
backward compatible — omit them and the CLI behaves exactly as before.

## Model & permissions

You don't have to hand-write `codingCmd`: the agent's connection panel emits
the selected provider's real executable and verified flags. Claude Code uses
its stable `opus` / `sonnet` / `haiku` aliases. Codex carries a neutral
`most-capable` / `balanced` / `fastest` tier that resolves against that
account's own live catalog. Cursor, opencode, Antigravity, and Hermes keep their
own model setting because no universal tier maps honestly onto their catalogs.
Unsupported permission choices are omitted from the UI. Change the command
later in `hilos-agent.json`; the daemon re-reads it between polls without
touching the token.

## Permissions / autonomy

There are two separate gates:

- **Room runtime permissions.** When the workspace has granted runtime
  permissions, current daemons put Claude Code, Codex, Cursor, and OpenCode
  behind the same server-authorized card flow. A tool ask pauses mechanically
  and resumes only after an eligible channel member chooses **Allow once**, an
  exact harness-suggested **Always** rule, or **Deny**. Cursor and OpenCode use
  ACP; Claude Code uses its permission-prompt tool; Codex uses `codex
  mcp-server` because `codex exec` has no approval transport. Once a relay is
  active, authority loss, expiry, cancellation, and transport failure all fail
  closed. A positively unavailable old-CLI transport is the compatibility
  exception: the daemon warns the room, then starts the ungated fallback.
  Explicit vendor bypass modes such as `opencode run --auto` or Claude Code's
  `--dangerously-skip-permissions` deliberately opt out of the cards.
- **The CLI's own mode.** Without a workspace runtime grant, `codingCmd` remains
  authoritative. The default Claude Code command uses
  `--permission-mode acceptEdits`: it may edit without prompting, but a headless
  command that needs additional approval can stall. For a fully independent
  local agent, `--dangerously-skip-permissions` can run any command in the repo
  you point it at, so use it only where that trust is acceptable.

  ```json
  { "codingCmd": "claude -p --dangerously-skip-permissions" }
  ```

- **Approve-before-push (`gate:true`), most cautious.** Independent of the two
  above — the agent still runs locally, but posts the proposed diff as a card and
  pushes only after you Approve. Pair it with either permission mode.

The default stays `acceptEdits`. Reach for `--dangerously-skip-permissions` when
you want a truly hands-off teammate, and keep `gate:true` if you'd rather review
before anything is pushed. Runtime cards and the push gate are independent: one
governs tools during the run, the other governs when the resulting code leaves
the machine.

## Hooks — keep a raw Codex, Claude Code, or Cursor session in the room

Keep working in the interactive coding tool you already use. Project hooks make
Codex, Claude Code, or Cursor visible on the agent's live card and bind a successful
hilos `post_message` / `post_report` to that exact provider session. With the
normal `hilos-agent` process running, a person's reply in the bound hilos thread
becomes the next turn in the same local session and checkout.

```sh
# Inside the repo you want to stream:
npx hilos-agent@latest hooks install

# Install only one provider, if you prefer:
npx hilos-agent@latest hooks install --codex
npx hilos-agent@latest hooks install --claude
npx hilos-agent@latest hooks install --cursor

# Or opt in every repo on this machine:
npx hilos-agent@latest hooks install --global
```

Claude Code and Cursor write lifecycle entries into this repo. Codex needs one
entry in `~/.codex/hooks.json` because `codex exec` does not run repository
hooks. hilos keeps that entry project-scoped with a 0600 allowlist at
`~/.hilos/codex-hook-scope.json`, so other repos stay untouched unless you use
`--global`. Launching Codex below the opted-in repository root still works, but
a nested repository needs its own opt-in. If the allowlist is lost or malformed,
new installs fail closed instead of reporting from every repo.

Any hooks you already have are preserved. A pre-existing project-level hilos
Codex entry is moved out, with a `.bak` beside the changed file. Codex asks you
to review the home-level hilos hook once; open `/hooks` and trust the entry.
The installer copies the dependency-free hook code into a private, versioned
`~/.hilos/hook-runtime` and records its absolute entrypoint. A one-off npx run
therefore remains usable offline; no global install or PATH change is required.
Preview all three blocks without writing anything:

```sh
npx hilos-agent@latest hooks print
```

**Requirements:**
- For live progress from every tool event, a `~/.hilos/agent.json` with `url`
  and the owned agent's `token`; `channelId` is needed only for the fallback
  live card. The normal one-line `--join` flow does not need that file for
  replies: its token stays in daemon memory, and Hilos signs each session
  binding so the daemon can verify it before resuming local code.
- Keep `hilos-agent` running to pick replies up. Hooks only emit lifecycle
  events; the daemon is the consumer that waits on the server's wake/long-poll
  path and resumes the local session.

**What you get:**
- Team members see "Editing lib/x.ts" or "Running pnpm test" on the agent's live
  card as each tool fires — without you doing anything beyond the install.
- A successful hilos post binds its returned message to this provider session.
  A person's later reply to that exact thread resumes the same session while
  `hilos-agent` is running. Ambient messages, older thread history, and agent
  replies do not wake it. Current workspace roles are checked at pickup: guests,
  removed people, and unknown authors remain advisory and cannot start code.
- Every initial mention job is also signed for its exact agent-token row and
  answer room after final server revalidation. The daemon keeps that proof on a
  job-local MCP client, so concurrent rooms cannot exchange project context. A
  guest-visible room may be explicitly allowed to run code, but its task still
  cannot pull workspace memory, Docs, Tasks, sibling conversations, or external
  context into the answer.
- The resumed turn receives bounded thread, room, and member context. Codex also
  gets a random loopback-only Hilos MCP URL for that turn, so it can search any
  room its linked owner can access when that owner minted the current key,
  without receiving the bearer token. Regenerate an older key from Connect to
  enable that inheritance. Admin-issued keys and other people's private rooms
  stay outside the context. Hilos signs the turn's room into a short-lived
  claim tied to that exact agent-token row; the loopback fixes the claim in an
  upstream header that the coding child cannot replace. A missing, malformed,
  cross-token, or conflicting room claim is refused, and a guest-visible turn
  cannot use workspace-wide tools to pull private sibling context into its
  answer.
- The room's normal execution gate still applies; a chat-only guest room cannot
  resume local code.
- Steps are coalesced into ~2s batches to keep traffic light.
- When a turn ends (`Stop`), the card settles to done. The next turn revives the
  same card — one card per session, not one per turn.
- Up to 20 unique files touched are surfaced so reviewers can glance at the scope
  before the report card arrives.

**Privacy:** project-level by default (only repos you opt into stream, including
Codex through its local allowlist). Hook state stays in
`~/.hilos/hook-state` and contains session ids, checkout paths,
hilos message ids, an opaque server-signed binding proof, a one-way credential
scope after verification, progress steps, and any completed result waiting for
a delivery retry — never the bearer token or coding transcript. Kill
switches: `HILOS_HOOKS=off` pauses streaming and new bindings;
`HILOS_REPLY_BRIDGE=off` pauses inbound replies. The hook always exits 0 — it
will never interrupt or break your CLI session.

## Security

The daemon runs a coding agent that can execute code in your repo — exactly as if
you ran it in your terminal — and uses *your* local `git`/`gh` to push. By default
it opens a PR (nothing is force-merged; you review the PR, and merge/close run via
hilos's GitHub App only for workspace owners/admins). Want a human checkpoint
before anything is pushed? Set `"gate": true`. Keep your token in the config file
or `HILOS_TOKEN`, never in shared shell history.

### Durable activity, not raw output

On a current hilos server, daemon-launched Claude Code, Codex, Cursor, and
OpenCode repo runs automatically keep the same bounded activity facts used by
the live card—phases, tool/file activity, notes, reported usage, and completion—
in hilos's runtime-neutral event record. Writes are batched, retry-safe,
bounded to two one-second attempts, re-authorized and redacted on the server,
and never allowed to fail the coding run. Raw stdout is not sent by this path.
An older server simply leaves it off.

### Run transcripts are opt-in

The room gets what a teammate needs to see: a plan, live progress, a report, a
PR. The coding tool's raw stream is **not** part of that by default. Current
servers do keep a bounded, redacted set of structured activity facts through
the runtime-neutral event protocol described above; that is not a transcript.

Set `"uploadTranscripts": true` and the daemon, after posting its report, sends
the tail of that run's stream to hilos, where it becomes the same transcript a
hosted run gets: openable from the report card, readable only by workspace
members, never by guests.

It is off until you turn it on, because every other option here changes how work
happens on your machine and this one moves bytes off it. When on: the last ~1 MB
of the run, cut at a whole record; credentials redacted here before sending and
again on arrival; a permission-gated run records its tool calls too, not just
the assistant's prose; each round of an iterate appends to the previous round
rather than replacing it; and the upload is never able to fail your run,
whatever goes wrong with it.

`HILOS_UPLOAD_TRANSCRIPTS=1` turns it on, `=0` forces it off, and either
overrides the config file. Turning it off takes effect on the next run, with no
restart — and **deleting** the key counts as off, not as "leave it as it was".

## Flags

`--join <blob>` · `--join-stdin` · `--channel <id>` · `--config <path>` ·
`--url <endpoint>` · `--token <token>` ·
`--coding-cmd <cmd>` · `--coding-model <tier>` · `--chat-cmd <cmd>` ·
`--web-search` · `--no-web-search` · `--once` · `--backfill` · `--gate` ·
`--no-gate` · `--no-reply-bridge` · `--version` · `--help`. Hook installation
also accepts `--global` or one of `--claude`, `--codex`, and `--cursor`.

`--token` remains only for compatibility with older scripts. Command-line
arguments can be visible to other processes on the machine, so use
`--join-stdin`, `HILOS_TOKEN`, or the private config file for credentials.
Likewise, prefer `--join-stdin` over the legacy `--join <blob>` form for a new
connection.

`hilos-agent doctor` checks Node against the package's minimum version, both
configured CLIs, native web configuration, the hilos connection, the local seat
lock, and the config file and working folder. It returns JSON and exits with
code 1 if any check fails; add `--human` for one readable line per check. It
accepts the same join code, `--config`, and command overrides as the daemon.
Missing CLI checks include an install hint. The Cursor CLI (`cursor-agent`)
is installed separately from the Cursor app. The lock is released immediately
after the check; `contended` means another daemon holds that seat.

Keep the daemon in a separate terminal or a detached process that survives
your IDE agent's tool call. Confirm `watching: @-mentions` before calling it
online. The `hilos-connect` skill walks IDE agents through this setup.

See `hilos-agent --help` for the `doctor`, `init`, `webmcp`, `web doctor`, and `hooks`
subcommands.

Env: `HILOS_TOKEN`, `HILOS_URL`, `HILOS_CHANNEL`, `CODING_CMD`,
`HILOS_CODING_MODEL`, `HILOS_CHAT_CMD`, `HILOS_WEB_SEARCH=1|0`,
`HILOS_ACP=1|0`, `HILOS_HEARTBEAT_MS`, `HILOS_PROGRESS_MS`,
`HILOS_CHAT_TIMEOUT_MS`, `HILOS_REPLY_BRIDGE=1|0`, `HILOS_ONCE=1`,
`HILOS_BACKFILL=1`, and `HILOS_UPLOAD_TRANSCRIPTS=1|0`.

## Releasing

Bump `version` in `package.json`, merge, wait for main CI, then tag that commit
`hilos-agent-v<version>` and push the tag. The `npm-publish` workflow requires
that exact version, a commit contained in `main`, and a successful `verify`
check. It packs and clean-installs the artifact on Node.js 20, 22, and 24 before
publishing, then installs the registry copy and checks its version and help.
A manual workflow dispatch is always a dry run and cannot publish. The workflow
prefers npm trusted publishing's short-lived GitHub OIDC identity. The registry
trust is configured for `pablostanley/hilos`, `npm-publish.yml`, no GitHub
environment, and direct publishing. `NPM_TOKEN` remains as a fallback until one
real tagged release proves OIDC end to end. After that proof, remove the
workflow fallback, revoke the npm token, and delete the GitHub secret (1094,
1211, 1228). Because the source repository is private, npm will not attach a
public provenance attestation even when the publish itself uses OIDC.

## Browser agents and WebMCP

A WebMCP-enabled browser can use the signed-in hilos workspace directly.
Open Settings → Connections to check page-tool registration. Start with
`get_hilos_context`, then `navigate_hilos`; Docs, Tasks, rooms, activity and
onboarding register their own commands. No personal token or plugin is needed
for that browser session. See [WebMCP setup](https://hilos.sh/docs/webmcp).

The plugin and coding-client skills use remote MCP. They do not make Claude
Code, Codex, or Cursor into browser WebMCP consumers. For background work, keep
the personal or named-agent MCP connection. The local daemon's optional
`hilos-agent webmcp` bridge uses an isolated signed-in profile and exact
person-approved read tools. Its `tools` response distinguishes native from
limited imperative compatibility mode. Rediscover after navigation; calls bind
to the inspected page and never retry on site-provided error text.
