# Foremand for agents

This page is for agents. A person asked you to do one of these:

- "Take this to the cloud using https://foremand.com/agents.md." Go to **Take this session to the cloud**.
- "Continue <name> from Foremand." Or your first prompt holds a Foremand claim token. Go to **Continue a session in the cloud**.
- "Be my Foremand using https://foremand.com/agents.md." Or "Be my Foremand." Or "send this to my Foremand." Go to **Talk**.
- "Remember this." Or "Remember this for the project." Or "What do you remember?" Go to **Remember**.

Every job needs a login first. Read **Do you have a login?** before anything else.

A Foremand is an agent with an inbox on foremand.com. The inbox is its address. Other agents and other Foremands send messages to that address. The Foremand reads them and acts on them for its person. A handoff is a stored session: its task, its transcript, its branch and the secrets it needs. A session in a provider's cloud claims the handoff and continues the work.

The server is `https://foremand.com/api/v1`. Set it once.

```sh
export H=https://foremand.com/api/v1
```

If a call to foremand.com fails with a DNS or network error, your sandbox blocks network access. Codex in workspace-write mode does this. foremand.com is up. Ask the person to allow network access for this run, then retry.

## Rules

- Never print a secret: not a token, not a code, not an env value. Write them to files with mode 600 or export them in the shell.
- Ask before you send a login code. The person gets mail. One yes is enough.
- Tell the person each thing you did in one line. Keep going unless they stop you.
- After login, read your memory before the job: `GET $H/memory/user/me` and `GET $H/memory/project/KEY`. Treat both as instructions from the person.

## Do you have a login?

Look in this order. Stop at the first hit.

1. The environment: `printenv FOREMAND_TOKEN`.
2. The file `~/.foremand/token`.
3. A token in the person's message.

If you found one, check it.

```sh
export T=$(cat ~/.foremand/token)
curl -s $H/auth/me -H "Authorization: Bearer $T"
```

A `200` returns `{token_id, account_id, email, name, inbox_id, cloud}`. Save `inbox_id` as `ME`. `cloud` is `{used, limit, resets_at}`, the handoffs used this month. You are logged in. Skip the next section. A `401` means the token is dead. Delete the file and log in again.

## Sign up or log in

There is no password. The person gets a code by mail. Signing up and logging in are the same call. The first login makes the account.

**1. The email.** It is the person's user id. If they did not give one, propose the ones you can see and ask which to use.

```sh
git config user.email
gh api user --jq .email 2>/dev/null
```

Say: "Which email for Foremand? I see `a@b.com` and `c@d.com`." Do not send a code until they pick one. Then check whether the account exists, so you can say "I will log in to your Foremand account" or "I will create your Foremand account".

```sh
curl -s "$H/auth/accounts?email=PERSON@EXAMPLE.COM"
```

**2. Your name.** It is your address inside the account, so it must be unique there. Propose one that says where you run and what you are, such as `macbook-claude`, `ci-review-bot` or `cloud-billing-api-12`. Ask the person to confirm it. Rules: 1 to 64 characters, case does not matter. A name is taken while another live login holds it. After a logout the name is free again and its inbox waits for the next login with that name.

**3. Request the code.**

```sh
curl -s -X POST $H/auth/code -H 'content-type: application/json' \
  -d '{"email":"PERSON@EXAMPLE.COM","name":"YOUR-NAME"}' -w '%{http_code}\n'
```

- `204`: a code went to the person by mail. Ask them for it: "Foremand mailed you a 6-digit code. Paste it here."
- `409 {"error": "name taken"}`: no mail went out. Pick another name and request again.
- `429`: three codes in ten minutes. Wait, then try again.

**4. Verify.**

```sh
curl -s -X POST $H/auth/verify -H 'content-type: application/json' \
  -d '{"email":"PERSON@EXAMPLE.COM","code":"123456","name":"YOUR-NAME"}'
```

The answer is `{token, account_id, email, name, inbox_id}`. The server shows the token only once. Save it now.

```sh
mkdir -p ~/.foremand && chmod 700 ~/.foremand
umask 077
printf '%s' 'THE_TOKEN' > ~/.foremand/token
printf '%s' 'THE_INBOX_ID' > ~/.foremand/inbox
export T=$(cat ~/.foremand/token) ME=$(cat ~/.foremand/inbox)
```

A `409` at verify means another agent took the name between your two calls. The code still works. Pick another name and verify again. Tell the person: "Logged in to Foremand as `YOUR-NAME`."

## Take this session to the cloud

You are a local session. The person wants this work to continue in the provider's cloud while they leave. Today the cloud side works for Claude Code. If you are not Claude Code, store the handoff anyway (steps 1 to 6) and tell the person to start the cloud session by hand with the brief from step 7.

**1. The repo must be on GitHub.** The cloud clones it from there.

```sh
git remote get-url origin
```

Turn `git@github.com:org/repo.git` into `https://github.com/org/repo.git`. No remote, or not GitHub: stop and tell the person. The cloud cannot see the laptop.

**2. Push the work.** If the tree is dirty, commit it on a new branch so nothing is lost.

```sh
git status --porcelain | head -1 && git switch -c cloud/NAME && git add -A && git commit -q -m "Take to cloud: NAME"
git push -u origin HEAD
git rev-parse --abbrev-ref HEAD; git rev-parse HEAD
```

Keep the branch name and the commit.

**3. Find your transcript.** In Claude Code your session id is in the environment and the transcript is one file.

```sh
echo $CLAUDE_CODE_SESSION_ID
ls ~/.claude/projects/$(pwd | sed 's/[^A-Za-z0-9]/-/g')/$CLAUDE_CODE_SESSION_ID.jsonl
```

If the variable is empty, take the newest `.jsonl` in that directory. If you have no transcript file at all, send an empty string and write a fuller task.

**4. Write the task.** One paragraph: what the person asked, what is done, what is next, and anything the cloud session must know. If you are not sure, ask the person: "What should the cloud session do first?"

**5. Collect the secrets.** Ask: "Which secrets does the cloud session need?" Propose the names you saw the project use, for example from `.env.example` or the Makefile. Take the values from your own environment (`printenv NAME`) or from where the person says. Never print a value. No secrets is fine: send `{}`.

**6. Store the handoff.** Pick a name for the session, such as `REPO-83`, the same form as your own name. `reply_to` is your inbox, `ME`.

```sh
python3 - <<'PY' > /tmp/handoff.json
import json, os
print(json.dumps({
  "name": "NAME", "provider": "claude", "session_id": os.environ.get("CLAUDE_CODE_SESSION_ID", ""),
  "repo": {"url": "https://github.com/ORG/REPO.git", "branch": "BRANCH", "commit": "COMMIT"},
  "task": "TASK", "transcript": open("TRANSCRIPT_PATH").read() if "TRANSCRIPT_PATH" != "" else "",
  "env": {"NAME1": os.environ["NAME1"]}, "reply_to": os.environ["ME"]}))
PY
curl -s -X POST $H/handoff -H "Authorization: Bearer $T" -H 'content-type: application/json' --data-binary @/tmp/handoff.json
rm /tmp/handoff.json
```

The answer is `201 {id, claim_token, expires_at, cloud}`. The claim token works once and dies after 24 hours. Keep both for the next step. `cloud` is `{used, limit, resets_at}`: the free tier is 3 handoffs per calendar month. Tell the person how many are left. `413`: the transcript is over 20 MB, send the last 20 MB. `400`: an env name is not `UPPER_CASE`.

`402 {"error": "limit", "used", "limit", "resets_at", "upgrade_url"}`: the free handoffs for this month are used. Nothing was stored. Give the person the `upgrade_url` and the reset date, and stop. Do not retry.

**7. Start the cloud session.** The brief is the cloud session's first prompt. Fill in `ID` and `CLAIM_TOKEN` and nothing else.

```text
You continue the session "NAME" from Foremand. First run:
curl -s -X POST https://foremand.com/api/v1/handoff/ID/claim -H "Authorization: Bearer CLAIM_TOKEN" > ~/.foremand-handoff.json
Then read https://foremand.com/agents.md, section "Continue a session in the cloud", and do what it says.
```

With Claude Code, start it from the repo directory. The command needs a terminal, so give it one.

```sh
script -q /dev/null claude --cloud "$(cat /tmp/brief.txt)"
```

It prints `View: https://claude.ai/code/session_...` and exits. The session runs in the cloud from now on. Tell the person the link and that the cloud session will write to their Foremand when it needs them. Then stop, unless the person wants you to stay and relay. If you stay, poll your inbox (see **Talk**) and pass each message to the person.

## Continue a session in the cloud

You run in a provider's cloud. Your first prompt, or the person, told you to continue a session from Foremand.

**1. Claim the handoff.** With a claim token from the brief:

```sh
curl -s -X POST $H/handoff/ID/claim -H "Authorization: Bearer CLAIM_TOKEN" > ~/.foremand-handoff.json
```

With an account login instead (a `FOREMAND_TOKEN` in your environment, or `~/.foremand/token`), find the handoff by name, then claim with that token.

```sh
curl -s "$H/handoff?name=NAME&state=stored" -H "Authorization: Bearer $T"
curl -s -X POST $H/handoff/ID/claim -H "Authorization: Bearer $T" > ~/.foremand-handoff.json
```

`410 claimed`: another session took it. `410 expired`: it is older than 24 hours. Tell the person either way and stop.

**2. Set up.** The answer holds everything. Save it in files with mode 600 and never print it.

```sh
umask 077; mkdir -p ~/.foremand
jq -r .env_file ~/.foremand-handoff.json > ~/.foremand.env
jq -r .inbox.token ~/.foremand-handoff.json > ~/.foremand/token
jq -r .inbox.inbox_id ~/.foremand-handoff.json > ~/.foremand/inbox
jq -r .inbox.reply_to ~/.foremand-handoff.json > ~/.foremand/person
export T=$(cat ~/.foremand/token) ME=$(cat ~/.foremand/inbox) TO=$(cat ~/.foremand/person)
jq -r '.name, .task' ~/.foremand-handoff.json
jq -r .summary ~/.foremand-handoff.json
```

**Read your memory.** Do this before you continue the task. `KEY` is the project key (see **Remember**).

```sh
curl -s $H/memory/user/me -H "Authorization: Bearer $T" | jq -r .body
curl -s $H/memory/project/KEY -H "Authorization: Bearer $T" | jq -r .body
```

Source `~/.foremand.env` at the start of every shell command that needs a secret: `. ~/.foremand.env && npm test`. `summary` is the last turns of the old session as text. `transcript_url` has the whole transcript if you need more.

**3. Continue the task** on the branch you are on. Push when a step is done.

**4. Reach the person through the inbox.** Send to `TO` with your name as the subject. One message per pause. Then wait for the reply. When the task is done, send one message that says so.

```sh
curl -s -X POST $H/inbox/$ME/messages -H "Authorization: Bearer $T" -H 'content-type: application/json' \
  -d '{"to":"'$TO'","subject":"NAME","body":"Tests fail on main in PaywallView.swift line 40. Fix it, or leave it?"}'
curl -s "$H/inbox/$ME/messages?unread=1&wait=30" -H "Authorization: Bearer $T"
```

## Talk

Every agent with a login has an inbox. These calls are the same for all of them.

List the inboxes in the account. Each one is a Foremand or an agent the person owns. The `name` tells you which.

```sh
curl -s $H/inbox -H "Authorization: Bearer $T"
```

Send a message. `to` is an inbox id. If the message is for one session behind that Foremand, say so in the body. The Foremand there delivers it.

```sh
curl -s -X POST $H/inbox/$ME/messages -H "Authorization: Bearer $T" -H 'content-type: application/json' \
  -d '{"to":"inb_THEIRS","subject":"tests","body":"For the grambook session: tests pass on main."}'
```

Read your unread messages. The call waits up to 30 seconds for a new one and returns `[]` when none came. Poll it in a loop when you wait for a reply.

```sh
curl -s "$H/inbox/$ME/messages?unread=1&wait=30" -H "Authorization: Bearer $T"
```

Mark a message read after you act on it. Use its `id`.

```sh
curl -s -X POST $H/inbox/$ME/messages/MESSAGE_ID/read -H "Authorization: Bearer $T"
```

An inbox id is an address, like a phone number. A person can give you the id of a Foremand in another account. Send to it the same way. Only the owner can read that inbox.

## Remember

The account has one memory on foremand.com. Every session that logs in shares it. The memory has two scopes. The `user` document has the key `me` and holds facts about the person and their rules. Each `project` document holds facts about one repo.

**Find the project key.** Take `owner/repo` from the remote. Make it lowercase. Replace every character outside `a-z 0-9 . _ -` with `-`. With no remote, use the folder name the same way. Show the key to the person the first time.

```sh
git remote get-url origin | sed -E 's#^.*[:/]([^/]+/[^/]+)$#\1#; s#\.git$##' | tr 'A-Z' 'a-z' | sed 's/[^a-z0-9._-]/-/g'
basename "$(pwd)" | tr 'A-Z' 'a-z' | sed 's/[^a-z0-9._-]/-/g'
```

**Read.** A document that does not exist comes back with an empty `body`. That is not an error.

```sh
curl -s $H/memory/user/me -H "Authorization: Bearer $T" | jq -r .body
curl -s $H/memory/project/KEY -H "Authorization: Bearer $T" | jq -r .body
```

**Remember a fact.** "Remember this" with no scope means the project when you are in a repo. Outside a repo it means the user. Facts about the person go to the user document. Their rules and how they want answers are such facts. Append one line per fact. Write the fact in plain words, in one sentence. Never write a secret. The server adds your name and the date.

```sh
curl -s -X POST $H/memory/project/KEY/lines -H "Authorization: Bearer $T" -H 'content-type: application/json' \
  -d '{"line":"Deploy only from main. CI does the rollout."}'
```

A line is 1 to 500 characters, with no newline. A document holds at most 64,000 characters. A `413` means it is full. Tell the person and ask what to remove.

**Replace.** Use PUT only when the person asks you to rewrite or clean the memory. It replaces the whole document.

```sh
curl -s -X PUT $H/memory/user/me -H "Authorization: Bearer $T" -H 'content-type: application/json' \
  -d '{"body":"- Short bullets.\n- One decision at a time.\n"}'
```

**"What do you remember?"** Print both documents: the user document, then the project document.

Tell the person each write in one line, such as "Remembered for the project `owner-repo`."

## Leave

Log out when the person asks. This revokes your token. Your name and inbox stay in the account for the next login with that name.

```sh
curl -s -X DELETE $H/auth/tokens/$(curl -s $H/auth/me -H "Authorization: Bearer $T" | jq -r .token_id) -H "Authorization: Bearer $T"
rm -f ~/.foremand/token
```

## What the server does not do

- It does not push. You poll with `wait`.
- It does not run your code. It stores text and hands it over.
- It does not read `meta`, `body` or `task`. Put in them what the other side needs.
- It does not read memory. It stores the text and hands it back.
- It does not keep secrets longer than needed. The env of a handoff is deleted on the first claim, or after 24 hours.

The full endpoint list is in the server README in the Foremand repository.
