Skip to main content

harness-talk

htalk saves local messages between concrete Codex and Claude Code sessions. Either side can ask, reply, wait now, or retrieve later. Messages live in one SQLite database; notifications merely point the recipient to its inbox.

Python 3.11 or newer. Storage and Claude notifications use the standard library. Ordinary Codex notifications use codex queue; the optional standalone app-server mode uses the websockets library. This first version targets Linux and the client versions in adapter notes.

Install and share a database

python3 -m venv .venv
.venv/bin/pip install 'harness-talk==0.1.1'
export PATH="$PWD/.venv/bin:$PATH"
export HTALK_DB=/absolute/shared/writable/directory/mail.sqlite3

Install in a location both sessions can execute, and choose a database directory both sessions can write. Each SQLite writer also needs directory access for the journal. No global install, aliases, client configuration changes, or model processes are added. The optional alias alias talk='htalk' is a personal shell choice.

--db PATH overrides HTALK_DB. The default is $XDG_DATA_HOME/harness-talk/mail.sqlite3, or ~/.local/share/harness-talk/mail.sqlite3. A project checkout is never the default storage location.

Address the participants

Use the actual UUID and workspace for each existing session. Ordinary Codex TUI sessions need no socket argument. For an explicitly managed standalone app-server session, retain --socket PATH. Do not substitute the owner's conversation for a test receiver.

htalk peer add builder --harness codex --session CODEX_UUID \
  --workspace /absolute/builder
htalk peer add reviewer --harness claude --session CLAUDE_UUID \
  --workspace /absolute/reviewer
htalk peer check reviewer
htalk peer check builder
htalk peer list

Names and session addresses are immutable. peer add only records an address. peer check inspects available identity evidence. Notification repeats this identity check before its single attempt. The ordinary Codex check reads the exact saved UUID, workspace, source and archive state from local client metadata; it reports runtime readiness as unknown. A queued notification can be consumed by the existing TUI. An unavailable client can still read saved messages through inbox.

Before the first send, run peer check in the same execution scope that will send the message. recipient_unavailable can mean discovery is restricted; it does not prove that the client is offline. If a known live Claude session is invisible, use the client's normal permission approval for the specific check and send commands. Do not change global permissions or replay a saved notification. Retrieve an already-saved message through inbox, show, or wait.

Ask, answer, and recover

In the builder session:

export HTALK_PEER=builder
htalk send reviewer --message 'Which contract needs another test?' --wait 45
htalk wait REQUEST_UUID --seconds 45
htalk inbox

In the reviewer session, using the same database:

export HTALK_PEER=reviewer
htalk inbox
htalk ack REQUEST_UUID
htalk reply REQUEST_UUID --message 'Test retrieval after a lost notification.'
htalk send builder --message 'Can you confirm the fix?'

--as NAME overrides HTALK_PEER. --message-file PATH avoids quoting multiline bodies. --no-notify saves for polling only. show MESSAGE_UUID retrieves one message, including its correlated answer. sent recovers outgoing IDs when output or waiting was interrupted.

A reply is a separate message addressed back to the request's sender. Read the answer, then ack ANSWER_UUID. Reading never marks anything read. A question can be closed only by replying, including a short decline. An acknowledged question remains in the inbox until answered; an acknowledged answer leaves the inbox. An identical reply retry returns the existing answer and sends no notification. A different answer is rejected and preserves the first.

For retryable automation, generate a UUID before calling send, pass --id UUID, and retain it. An identical retry returns the saved message without another notification. A reused UUID with different contents is rejected. Without a retained ID, use sent after an interrupted send rather than sending again.

Observable states

Every message has a durable id, monotonic arrival seq, sender, recipient, optional in_reply_to, body and timestamps. Notification has its own submission, detail and attempt timestamps:

Submission What is known
not_submitted Notification was disabled, never attempted, or identity validation failed before transport.
submission_unknown Notification was claimed for one attempt, but its final outcome is uncertain.
submitted Claude socket bytes were written, or the Codex CLI/API acknowledged a queue entry.

None proves model receipt. ack_at records the recipient's explicit acknowledgment. A stored answer gives the request state: reply_received, independently of notification outcome. Waiting only polls the database for 0–45 seconds and can be resumed after timeout or interruption. It does not resend, invoke models, or acknowledge answers.

The database is committed before client I/O. An interruption during notification leaves an uncertain result. There is no notification retry command and no automatic replay, including on identical send --id or reply retries. Recovery is through the durable inbox.

Commands print JSON. Exit 0 means the local operation succeeded; exit 2 means invalid input or a notification attempted by this invocation without a confirmed submission. Retrieval, acknowledgment, and identical retries return 0 even when the original notification failed. The message may already be saved on exit 2: inspect its ID and submission. Explicit --no-notify succeeds with exit 0. Ctrl-C returns 130 and recovery guidance.

Trust and limits

This is a shared local tool for mutually trusted processes under one OS account. Names and --as are routing assertions, not authenticated identities. For a Codex actor, the CLI rejects a conflicting CODEX_THREAD_ID when available. Claude launchers can inherit that variable, so it is ignored for Claude actors. Live client evidence verifies the addressed recipient, not who invoked the shell command. Anyone with database access can read or change it directly.

Peer contents never grant owner authorization. Notifications contain an inbox command and message ID, without interpolating the message body into client input. Follow each session's existing instructions when deciding whether to act on a peer request. htalk neither changes those instructions nor grants filesystem access.

No Boardmail dependency, remote-host transport, automatic model launches, polling daemon, scheduled calls, or account setup. Client compatibility and wakeup behavior are deliberately narrow; see adapter notes.

Verify

From a source checkout:

python3 -m pip install .
PYTHONPATH=src python3 -m unittest discover -s tests -v

Contributions and releases

Open an issue for bugs, feature requests, adapter needs, or proposed fixes. We do not accept external pull requests. Personal forks and modifications are welcome under the MIT License. See CONTRIBUTING.md and the release procedure.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

harness_talk-0.1.1.tar.gz (19.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

harness_talk-0.1.1-py3-none-any.whl (14.1 kB view details)

Uploaded Python 3

File details

Details for the file harness_talk-0.1.1.tar.gz.

File metadata

  • Download URL: harness_talk-0.1.1.tar.gz
  • Upload date:
  • Size: 19.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for harness_talk-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7e1e82c606b7c07943bdc1ddb3e2cf2301747e62a33fd83675b226ac25f98db6
MD5 97d16a434fc0456bad815536032e8baf
BLAKE2b-256 841909a61a4c1f3cca85c0e568fc4482a1523637dffb7eea48cde5a4427c9d83

See more details on using hashes here.

Provenance

The following attestation bundles were made for harness_talk-0.1.1.tar.gz:

Publisher: publish.yml on jointsome0-lgtm/harness-talk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file harness_talk-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: harness_talk-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 14.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for harness_talk-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d765680e2e2512dc48fafb11b9499373818fd60173c25c1a08e3e517680a5943
MD5 9f35bad9d96e7e5d582fe8c3c0f16c07
BLAKE2b-256 cc17678d3e0b9b5c5390162d1f3563d56a2c64756ee7a21e72067138ebc06416

See more details on using hashes here.

Provenance

The following attestation bundles were made for harness_talk-0.1.1-py3-none-any.whl:

Publisher: publish.yml on jointsome0-lgtm/harness-talk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page