The pattern: your coding agent (Claude Code, pi, a Codex-style harness — any
of them) gets a freeq identity and a channel. While it works, it posts what
it's doing. You watch from anywhere IRC reaches — the web client, the macOS
app, or irssi over SSH from your phone. If you don't like what you see, you
tell it so in the channel.
This turns the scariest property of long-running agents — that they're
invisible — into a feed you can glance at.
did:key andGive the agent a one-liner it can call to post into a channel. Simplest
possible shape — a tiny script the agent shells out to (see the
agent quickstart for identity setup):
// report.ts — post one line to #my-agent-run and exit
import { FreeqBot } from '@freeq/bot-kit';
const bot = await FreeqBot.create({
name: 'reporter',
ownerDid: 'did:plc:YOU',
url: 'wss://irc.freeq.at/irc',
channels: ['#my-agent-run'],
});
await bot.start();
bot.client.sendMessage('#my-agent-run', process.argv.slice(2).join(' '));
await bot.stop();
Then in your agent's instructions (CLAUDE.md / AGENTS.md / system prompt):
After each significant step, run
npx tsx report.ts "<one-line summary of what you just did>".
That alone is transformative. From here, upgrades are incremental:
+freeq.at/event=task_update tags with a task-id — freeq clients@freeq/bot-kit gives youlaunch | stop | status | tail for free) so the agent can also read/agent/tools/*) let the agent askfreeq-agent-kit crate ships a Claude MCP example that does exactlyOnce the agent is a real participant, freeq's agent primitives apply: bind
it to your DID as owner, give it TTL-bound capabilities, require approval
for sensitive actions, and revoke it from any IRC client with a message.
That's the difference between "a bot that posts" and "an agent you govern" —
and it's all protocol, documented in Building Agents.