culture console
culture console opens irc-lens — a localhost aiohttp + HTMX + SSE web console — for a running AgentIRC server. It is a passthrough wrapper: arguments after the subcommand are handed to irc-lens verbatim, with one culture-owned shim that resolves a culture server name into the right --host/--port/--nick flags.
Quick start
culture server start --name spark
culture console spark # opens http://127.0.0.1:8765/
Equivalent to:
culture console serve --host 127.0.0.1 --port 6667 --nick spark-<you>
First-run config
irc-lens 0.5.x requires a config file at ~/.config/irc-lens/config.yaml (or $XDG_CONFIG_HOME/irc-lens/config.yaml). On a fresh machine, culture console auto-initializes a starter dev-mode config there before invoking irc-lens serve, so first-run usage just works. The auto-init only runs when:
- the user did not pass
--config <path>(an explicit path means the user is managing the file themselves), and - the default path does not already exist.
To opt out of the auto-init entirely, run irc-lens config init yourself and place the file at the default path (or supply --config on every invocation). See irc-lens config init --help for available flags.
Verbs
| Verb | Behaviour |
|---|---|
culture console <server> | Resolve server’s host/port/nick, run irc-lens serve. |
culture console serve … | Pure passthrough to irc-lens serve. |
culture console explain | Pure passthrough to irc-lens explain. |
culture console overview | Pure passthrough to irc-lens overview. |
culture console learn | Pure passthrough to irc-lens learn. |
culture console stop | Culture-owned. Stop the locally-running console. |
culture console --help | irc-lens’s own help. |
stop is reserved by culture and shadows any culture server literally named stop (use culture console -- stop to disambiguate, though the combination is unlikely to be useful).
Port-conflict UX
irc-lens binds a single web port (default 8765). When that port is already in use, culture inspects the binder before letting the bind fail:
-
Same target already running. If the existing console is yours and is serving the same server/nick, culture prints
culture console is already running for 'spark' at http://127.0.0.1:8765/and exits
0. Open the URL in your browser; no new process needed. -
Different target on the same port. If the existing console is yours but is serving a different server, culture prints a 3-bullet hint and exits
1:culture console is already running for 'thor' (thor-ada) on http://127.0.0.1:8765/ What to do: - Open the existing console: http://127.0.0.1:8765/ - Stop it and start fresh: culture console stop && culture console spark - Or run side-by-side: culture console spark --web-port 8766Culture never auto-kills another running console — that decision stays with you.
-
Foreign irc-lens. Port bound, an HTTP probe identifies an irc-lens fingerprint, but culture has no pidfile for it (e.g. it was started outside
culture console). Culture prints a hint pointing atss/lsofand exits1. -
Foreign owner (not irc-lens). Culture falls through; irc-lens emits its own
cannot bind web port …error. That message is the right one for arbitrary processes — culture does not double-wrap it. -
Stale pidfile. If the recorded PID is dead or no longer a culture process, culture quietly cleans up the state files and proceeds.
State files
State is keyed per web port — running consoles side-by-side on different --web-port values keeps each instance’s metadata independent. While a console is running on port <P>, three files exist under ~/.culture/pids/:
| File | Contents |
|---|---|
console-<P>.pid | PID of the culture console process bound to port <P>. |
console-<P>.port | The web port <P> (matches the filename, kept for pidfile.list_servers()-style symmetry). |
console-<P>.json | Sidecar with pid, server_name, nick, host, irc_port, web_port. |
A console on the default port owns console-8765.{pid,port,json}; a side-by-side run on --web-port 8766 owns console-8766.*.
These files are removed deterministically when irc-lens exits (the shim wraps the call in try/finally rather than registering an atexit handler — the latter would fire after pytest’s monkeypatch undo and could delete real state during the test suite). culture console stop also removes them.
culture console stop
culture console stop # default --web-port 8765
culture console stop --web-port 8766 # stop a side-by-side console
- Reads
~/.culture/pids/console-<P>.pidfor the requested port (default8765). - Absent slot → prints
no culture console running on port <P>.and exits0(idempotent). - PID is dead → cleans up state files and exits
0. - PID belongs to a non-culture process → exits
1and preserves the state files (we won’t trash state we couldn’t validate; thepidfile.is_culture_processfail-closed comment inculture/pidfile.pyexists for exactly this case). - Otherwise sends
SIGTERM, waits up to 5 seconds, re-validatesis_culture_processbefore escalating toSIGKILL(so a PID recycled during the grace window doesn’t get an errant kill), then removes state files.
stop does not affect the AgentIRC server or any agents — only the local console process for the requested port.
See also
culture devex— sibling passthrough for agex-cli, same plumbing.culture afi— sibling passthrough for afi-cli.docs/superpowers/specs/2026-05-05-culture-console-design.md— original design.