Skip to main content

Runs Claude Code sessions in tmux on your machine and streams them to a Famulus backend

Project description

famulus-worker

The machine-side half of Famulus. It runs Claude Code sessions on your computer, where your repositories, your tooling and your claude login already live, and reports progress back to the Famulus backend.

Connections are outbound only. The worker dials the backend over WebSocket, so your machine needs no open ports, no port forwarding and no public IP.

┌─────────────┐   outbound ws    ┌──────────────┐
│  worker     │ ───────────────► │   backend    │ ◄──── browser
│  (your Mac) │ ◄─────────────── │  (anywhere)  │
└─────┬───────┘   tasks, replies └──────────────┘
      │
      ▼  tmux session per task
   `claude` ── writes result JSON ── picked up by the worker

⚠️ Read this before installing

The worker starts claude with --permission-mode auto and pre-accepts the workspace trust prompt, because a pipeline can't answer interactive dialogs. In practice that means:

  • Claude will read, write and delete files in the working directory you configure, and run shell commands there, without asking for confirmation.
  • Task titles, descriptions and imported ticket text are fed into that session as instructions. Treat anything you import as untrusted input. A hostile ticket description is a prompt-injection vector that can reach your shell.
  • The backend can ask the worker to open an interactive terminal on this machine, relayed to whoever is authenticated to the web UI.

Run it against directories you're willing to let an agent modify, with a backend only you can reach. See SECURITY.md for the full trust model.


Requirements

Install

uv tool install famulus-worker
Other installation methods
pipx install famulus-worker          # isolated, also fine
pip install famulus-worker           # into the current environment

# from a checkout
git clone https://github.com/getfamulus/famulus-worker && cd famulus-worker
uv sync && uv run famulus-worker --help

Run

famulus-worker --api http://localhost:8000 --worker-token "$FAMULUS_WORKER_TOKEN"

The token has to match the backend's FAMULUS_WORKER_TOKEN, or FAMULUS_AUTH_TOKEN if you didn't configure a separate worker credential. On success you'll see:

Worker starting (reverse tunnel mode)
  API:    http://localhost:8000
  Claude: /opt/homebrew/bin/claude
Connected to backend relay

Options

Flag Env Default Description
--api FAMULUS_API http://localhost:8000 Backend base URL
--worker-token FAMULUS_WORKER_TOKEN none Worker credential (preferred)
--token FAMULUS_TOKEN none Fallback credential if no worker token is set
--poll-interval none 3 Seconds between task polls

Keeping it running

macOS launchd example

Save to ~/Library/LaunchAgents/dev.famulus.worker.plist, then launchctl load ~/Library/LaunchAgents/dev.famulus.worker.plist.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key><string>dev.famulus.worker</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/you/.local/bin/famulus-worker</string>
        <string>--api</string><string>https://famulus.example.com</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict><key>FAMULUS_WORKER_TOKEN</key><string>replace-me</string></dict>
    <key>RunAtLoad</key><true/>
    <key>KeepAlive</key><true/>
</dict>
</plist>

How it works

  1. Poll. Ask the backend for steps whose status is running, grouped by stage.
  2. Session. Ensure a detached tmux session per task (tr-<taskid>) running one persistent claude conversation keyed to the task id, so later stages keep context.
  3. Dispatch. Paste a stage prompt into the session via a tmux paste-buffer, never a shell string, so task text can't escape into your shell. Claude is asked to fan out one subagent per parallel job.
  4. Collect. Claude writes {"status","output"} JSON per job into <working_dir>/.tr/<task_id>/. The worker posts each result and deletes the file.
  5. Relay. On request, open a PTY (attaching to the task's tmux session when there is one) and stream it to the browser through the backend.

State lives in ~/.famulus/: pane logs, session and dispatch markers, attachment cache. Those markers are what make a restart adopt in-flight work instead of re-running it.

Worktrees (optional)

If a task asks for a git worktree, the worker runs ~/.claude/utils/worktree-new.sh <ticket-id> in the repository and expects it to print WORKTREE_PATH=<path>. Supply your own script at that path. There's a reference implementation in examples/worktree-new.sh.

Troubleshooting

Symptom Cause
Backend closed during auth, reconnecting… Token mismatch. It must equal the backend's FAMULUS_WORKER_TOKEN
claude cannot run: Login expired The CLI's login lapsed. Run claude on this machine, sign in, then re-run the task
Session … did not report ready claude was slow or isn't signed in. Run claude once by hand
Steps stay "running" forever No tmux, or Claude never wrote a result file. Open the live terminal to look
Worktree failed Your worktree-new.sh is missing or didn't print WORKTREE_PATH=

Development

uv sync
uv run famulus-worker --help
uv build

License

MIT, see LICENSE.

Project details


Download files

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

Source Distribution

famulus_worker-0.1.0.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

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

famulus_worker-0.1.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file famulus_worker-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for famulus_worker-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1410fadbc12ba2aec79b16c470d1c31d72fbc48aa5a0663a9efac57eb1b8e628
MD5 96db168696d6103c33c11797a042c3dd
BLAKE2b-256 82d79d9dee908ef7dffaf324109f2e486084a9845a2f42f469dfd8ef11864606

See more details on using hashes here.

Provenance

The following attestation bundles were made for famulus_worker-0.1.0.tar.gz:

Publisher: publish.yml on getfamulus/famulus-worker

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

File details

Details for the file famulus_worker-0.1.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for famulus_worker-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b36b2daf9e5d951184d71be3f955c67b49054c1a045efee2ae77e961d788ca63
MD5 f0fd192268d833f674b93604fff291f8
BLAKE2b-256 a87d9c6f89e418d2a98294db9a9c629e3baa919c0eb78d0ee537a6f9a5e7a016

See more details on using hashes here.

Provenance

The following attestation bundles were made for famulus_worker-0.1.0-py3-none-any.whl:

Publisher: publish.yml on getfamulus/famulus-worker

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page