selan.ai

Docs · Agents

Agents

selan agent-run runs a Claude Code agent with nobody watching, and prints a line per tool call while it works. A reviewer on every pull request, a nightly dependency sweep, whatever you write into .claude/agents/.

What it is

selan agent-run <agent> <message>

It runs one of the agents in your repository's .claude/agents/, headless. The run renders as it happens, not as a wall of text at the end:

▸ Bash  Show the full diff
▸ Read  internal/cli/agentrun.go
▸ Bash  Run the test suite
  x     Test Suites: 1 failed, 77 passed
· Four findings, one question.
─── success  104s  $0.36

It is the same launch as selan claude. Same session, same proxy, same company settings, same model resolution, same repository attribution. So an agent spends against your company's key, answers to the same per-user limits as a developer, and shows up in Usage and Logs like any other run.

It skips every permission prompt, and asks nothing first. An agent nobody is watching cannot answer a prompt, and a run that stops halfway to ask has failed, not paused. Naming the agent on the command line is the consent. Treat what the agent can reach as the boundary, not what it will be asked.

1. Mint a CLI token

A CI job has no browser, so it cannot selan login. An owner mints a token under Settings → CLI tokens and the job carries it in the environment as SELAN_TOKEN.

Give each job its own, and name it after the job. A token spends as itself, under an address like ci-review@tokens.selan.ai, so the job's bill shows up as the job in Usage and Logs instead of landing on whoever set it up. You can revoke it from the same panel, and the company-wide per-user spend limit applies to it as it does to a person.

# GitHub
gh secret set SELAN_TOKEN --body 'selanct_...'

# GitLab: Settings → CI/CD → Variables, Masked and Protected

More on running without a browser: docs → running unattended.

2. Write the agent

An agent is one Markdown file in the repository it works on, .claude/agents/<name>.md: front matter, then the instructions.

---
name: code-review
description: Reviews a branch's diff and writes review.md. Changes nothing, posts nothing.
tools: Bash, Read, Grep, Glob, Write
---

You review one branch's changes and write what you find to `review.md`.

Two things you must not do: change any code, and post anything anywhere. Write
`review.md` and stop. Something else decides what happens to it.

Three things in there are worth copying, whatever the agent does:

  • It writes a file; it does not post. The pipeline posts. The agent then needs no GitHub or GitLab token at all, and exactly one comment appears whatever the agent decided to do with its own tools.
  • tools: is a whitelist. A reviewer needs to read and run commands; it does not need Edit. Leaving it out is cheaper than telling it not to.
  • Your repository's conventions are already in context. Claude Code loads CLAUDE.md itself, so an agent that restates your house style is maintaining a second copy of it. Tell it to work against that file.

3. Run it in CI

Four steps, whatever the CI: check out deep enough to see what you are working on, install selan and Claude Code, run the agent with SELAN_TOKEN in the environment, and do something with the file it wrote. The variable naming the workspace is the CI's own: $GITHUB_WORKSPACE on Actions, $CI_PROJECT_DIR on GitLab.

curl -fsSL https://dl.selan.ai/install.sh | sh
npm install -g @anthropic-ai/claude-code

selan agent-run code-review "…what to do. Write the result to $GITHUB_WORKSPACE/out.md."

Give the agent an absolute path for anything it writes. Claude Code's Write tool takes absolute paths, so a bare filename leaves the agent to reconstruct the working directory. Where it guesses wrong, the file lands outside the workspace, the job stays green, and the step that was meant to pick the file up finds nothing.

A complete, working pipeline for both GitHub Actions and GitLab CI is on the code review page.

Good practice

  • Advisory, never a gate. continue-on-error on GitHub, allow_failure on GitLab, including on the step that posts. A model's opinion should not block a merge, and a red mark people learn to ignore is worse than no mark at all.
  • Set a timeout. An agent run ends when the model decides it is finished, which is not a bound. Twenty minutes is generous for most jobs.
  • Cancel the previous run on a re-push (a concurrency group keyed on the merge request), or two runs on two different commits finish in whichever order they finish.
  • One agent, one job. A reviewer that also fixes things is two behaviours sharing a prompt, and the second is why you will end up reading every diff it produces anyway.
  • On a self-hosted runner, install into the job's temp directory (SELAN_INSTALL_DIR="$RUNNER_TEMP/bin"), and put that directory on PATH before running the installer, or it helpfully adds a PATH line to the runner user's shell profile, once per job, forever.
  • Watch the first few runs. The run log prints the cost, and it lands in Usage under the token's own address.

The agents

Written up one at a time, with the pipeline that runs them: