Commit 80de94d8 authored by xuwang's avatar xuwang
Browse files

feat(agentic): run multi-identity in `claude agents`; drop tmux launcher



Make agent view the single supervised path:
- Each role command pins its own bot token at tick start
  (OTICA_SERVER_TOKEN_FILE=~/.otica-tokens/<role>.token if present), so all roles
  can share one `claude agents` terminal yet authenticate as distinct identities.
- Add `make agents-stop` (scripts/agent-stop.sh): stop this repo's background agent
  sessions via `claude agents --json` + `claude stop` (background-only, cwd-scoped;
  never the interactive session or other projects).
- Remove the tmux launcher (scripts/agent-tmux.sh, `make agents-multi[-stop]`) —
  superseded by agent view; runbook updated (agent-view stop keys, shared-checkout
  caveat).

Changelog: changed
Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
parent c0b4329d
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -4,7 +4,15 @@ allowed-tools: Bash(scripts/gl-flow.sh:*), Read
---

You are **Agent-integrator**. Run **one** tick, then stop. Merge at most ONE MR.
Your bot (from `OTICA_SERVER_TOKEN[_FILE]`) must differ from the MR author.
Your bot must differ from the MR author.

### 0. Identity — pin this role's token (so all roles can share one `claude agents`)
FIRST, before any GitLab call:
```
[ -f "$HOME/.otica-tokens/integrator.token" ] && export OTICA_SERVER_TOKEN_FILE="$HOME/.otica-tokens/integrator.token" || true
scripts/gl-flow.sh whoami      # confirm you are the integrator, not the author
```
(Headless/cron sets it before launch — no-op there.)

### 1. Find approved work
- `scripts/gl-flow.sh mr-list --labels "review::approved"`  (reviewer-approved)
+9 −3
Original line number Diff line number Diff line
@@ -6,9 +6,15 @@ allowed-tools: Bash(scripts/gl-flow.sh:*), Bash(git:*), Bash(make:*), Bash(make
You are **Agent-resolver**. Run **one** tick, then stop (the `/loop` re-invokes you).
Do at most ONE issue per tick so concurrent resolvers never collide.

### 0. Identity
Run `scripts/gl-flow.sh whoami` and remember your bot username. Your token comes
from `OTICA_SERVER_TOKEN[_FILE]` (default `~/.otica-token`); the repo from `GITLAB_REPO`.
### 0. Identity — pin this role's token (so all roles can share one `claude agents`)
FIRST, before any GitLab call, select this role's bot identity:
```
[ -f "$HOME/.otica-tokens/resolver.token" ] && export OTICA_SERVER_TOKEN_FILE="$HOME/.otica-tokens/resolver.token" || true
scripts/gl-flow.sh whoami      # confirm; remember your username
```
If no `resolver.token` exists you run as the default `~/.otica-token`. (Headless/cron
already sets the per-role token before launch, so the export is a no-op there.)
Repo comes from `GITLAB_REPO` (auto-detected from origin).

### 1. Triage (cheap, do every tick) — including human/system-created issues
Issues may be opened by the reporter agent **or by a human or another system**, so
+11 −2
Original line number Diff line number Diff line
@@ -4,8 +4,17 @@ allowed-tools: Bash(scripts/gl-flow.sh:*), Bash(git:*), Bash(make:*), Read, Grep
---

You are **Agent-reviewer**. Run **one** tick, then stop. Review at most ONE MR.
Your bot (from `OTICA_SERVER_TOKEN[_FILE]`) must be **different from the resolver**
GitLab will not let an author approve their own MR.
Your bot must be **different from the resolver** — GitLab won't let an author
approve their own MR.

### 0. Identity — pin this role's token (so all roles can share one `claude agents`)
FIRST, before any GitLab call:
```
[ -f "$HOME/.otica-tokens/reviewer.token" ] && export OTICA_SERVER_TOKEN_FILE="$HOME/.otica-tokens/reviewer.token" || true
scripts/gl-flow.sh whoami      # confirm you are the reviewer, not the author
```
This is what makes the reviewer a distinct identity even when every role runs in
one agent-view terminal. (Headless/cron sets it before launch — no-op there.)

### 1. Find work (including MRs opened by humans / other systems)
MRs may come from the resolver agent **or from a human or another system**. Gather both:
+4 −8
Original line number Diff line number Diff line
@@ -37,6 +37,10 @@ validate-scripts: ## detect *.sh referenced in recipes that don't exist in scrip
agents: ## supervise the agentic workflow loops in one terminal (claude agents)
	@scripts/agent-view.sh

.PHONY: agents-stop
agents-stop: ## stop this repo's background agent sessions started by `claude agents`
	@scripts/agent-stop.sh

.PHONY: agentic-tick
agentic-tick: ## run one headless workflow tick. make agentic-tick ROLE=<resolver|reviewer|integrator|reporter>
	@if [ -z "$(ROLE)" ]; then \
@@ -45,14 +49,6 @@ agentic-tick: ## run one headless workflow tick. make agentic-tick ROLE=<resolve
	fi
	@scripts/agent-tick.sh $(ROLE)

.PHONY: agents-multi
agents-multi: ## launch looped roles in tmux — a pane + worktree + bot identity per role
	@scripts/agent-tmux.sh

.PHONY: agents-multi-stop
agents-multi-stop: ## stop the tmux session and remove the per-role worktrees
	@scripts/agent-tmux.sh stop

.PHONY: agentic-bots
agentic-bots: ## manage per-role bot identities. make agentic-bots ARGS="provision-all|list|revoke-all|provision <role>|revoke <role>"
	@scripts/agent-bots.sh $(ARGS)
+25 −27
Original line number Diff line number Diff line
@@ -210,17 +210,30 @@ make agents # prints the dispatch lines, then opens agent view
# (reporter stays on demand — dispatch /agent-reporter "..." when you have one)
```
Keys: **Shift+Down** cycle sessions · **Enter** view a transcript · **Esc**
interrupt a turn. Sessions keep running while you step away; `claude --resume`
restores unexpired loops if you close and reopen.

> **Identity caveat:** background sessions all **inherit the launcher's
> environment** — there's no per-session env, so they share one
> `OTICA_SERVER_TOKEN[_FILE]` (i.e. one GitLab identity). Agent view is therefore
> the right fit for the **single-identity** setup (`~/.otica-token`). If you need
> distinct per-role identities (so reviewer/integrator ≠ MR author for real
> approvals), use separate processes instead — the 4-terminal layout below, or the
> unattended cron path, where each `agent-tick.sh` process sets its own
> `OTICA_SERVER_TOKEN_FILE`.
interrupt a turn (or stop a `/loop` mid-wait) · **Ctrl+X** stop a session (again
within 2s to delete it). Sessions keep running without a terminal — a supervisor
process hosts them — so `claude --resume` restores unexpired loops after you close
and reopen.

**Stop them all:** `make agents-stop` stops every background agent session
launched from this repo (`claude agents --json``claude stop`), leaving your
interactive session and other projects' sessions untouched. (Nuclear option:
`claude daemon stop --any` stops *all* background sessions everywhere.)

**Multi-identity in one agent view works** — even though background sessions share
the launcher's environment, each role command **pins its own bot token** at the
start of every tick (`OTICA_SERVER_TOKEN_FILE=~/.otica-tokens/<role>.token` if that
file exists, else the default). So once you `make agentic-bots ARGS="provision-all"`,
all three loops in one `claude agents` terminal authenticate as their own bots —
no tmux, no separate terminals. (Without bots, every role runs as `~/.otica-token`
= single identity.)

> **Shared working tree, one caveat:** all agent-view sessions share the launch
> checkout, and the resolver does `git switch` there each fix. The reviewer/
> integrator are unaffected (they read remote refs + the API, and `gl-flow.sh`
> exists on every branch), but **don't do manual git work in that checkout while
> the loops run** — run the agents from a **dedicated clone** if you want to keep
> hacking in your own `~/.otica` at the same time.

This is `/loop`-based, so it's still session-scoped (stops if you quit; 7-day loop
expiry). For unattended 24/7, use the cron deployment below.
@@ -263,21 +276,6 @@ With distinct identities, confirm each pane is a **different** GitLab user befor
relying on approvals — run `scripts/gl-flow.sh whoami` in each and check the
usernames differ (reviewer/integrator must not be the resolver who authored the MR).

### Supervised mode, one command (tmux) — `make agents-multi`
Automates the multi-pane layout: a tmux session with a pane per looped role
(resolver/reviewer/integrator), **each in its own git worktree** (so the resolver's
branch switches never disrupt the others) and **its own bot identity** (auto-picked
from `~/.otica-tokens/<role>.token`, falling back to `~/.otica-token`). Each pane
runs a tick loop and prints its log tail, so you can watch all roles at once.
```bash
make agents-multi          # launch; tmux attach -t otica-agents to watch
make agents-multi-stop     # kill the session + remove the worktrees
```
It warns if `reviewer`/`integrator` bots aren't provisioned (without them those
roles can't act on your own MRs). Worktrees live in `~/.otica-agents/` and persist
until `agents-multi-stop`. This is the easiest way to run the full multi-identity
workflow locally; for true 24/7 use cron below.

### Unattended deployment (OS cron, headless)
`scripts/agent-tick.sh <role>` runs **one** headless tick (`claude -p
"/agent-<role>"` with the per-role settings/model) and exits — run one manually
@@ -432,6 +430,6 @@ Maintainer). `make agents` runs it before opening agent view, and every headless
  privilege (auto-selected by `agent-tick.sh`).
- `scripts/gl-flow.sh` — GitLab REST dispatcher (incl. `check` pre-flight).
- `scripts/agent-view.sh` — supervised launch (`make agents`): pre-flight + open agent view.
- `scripts/agent-stop.sh``make agents-stop`: stop this repo's background agent sessions.
- `scripts/agent-tick.sh` — headless one-tick cron runner (per-role identity, settings, model, lock, logs).
- `scripts/agent-tmux.sh``make agents-multi`: tmux pane + worktree + bot per looped role.
- `scripts/agent-bots.sh` — provision/list/revoke per-role bot identities (`make agentic-bots`).
Loading