Operations¶
sharedcode has no supervisor of its own and does not pretend otherwise. Either you run it by hand, or you hand it to systemd. This page covers both, plus health checks, logs, maintenance, the local vLLM router and the SharedData worker pool. The behaviour described here was checked against the 0.1.0 wheel; where output is shown, it is real output.
Start, stop, status¶
Two ways to run the background pieces:
| You want | Commands |
|---|---|
| Everything at once, including the web UI | sharedcode-serve --detach, sharedcode-serve status, sharedcode-serve stop |
| Gateway and orchestrator only | sharedcode gateway start, sharedcode gateway status, sharedcode gateway stop |
| The web UI on its own | sharedcode web start, sharedcode web status, sharedcode web stop |
sharedcode-serve status prints one PASS or FAIL line per component
and exits non-zero if any fails. serve refuses to start a component
whose port is already taken, so it can never half-adopt a stack it did
not launch. When a component dies, it is reported by name and not
restarted.
sharedcode gateway restart bounces the gateway. Use it after you edit
config.json by hand.
Run as a service¶
On Linux with systemd, each long-running piece can install itself as a
systemd user unit under ~/.config/systemd/user/, then enable and
start it:
sharedcode gateway install-service # sharedcode-orchestrator.service + sharedcode-gateway.service
sharedcode web install-service # sharedcode-web.service
sharedcode telegram install-service # sharedcode-telegram.service
sharedcode whatsapp install-service # sharedcode-whatsapp.service
--no-enable and --no-start write the units without turning them on.
The gateway, orchestrator, web and Telegram units use Restart=always;
the WhatsApp unit uses Restart=on-failure. The gateway's unit also
disables systemd's start rate limit on purpose, so a crash loop keeps
being restarted rather than giving up. Both gateway units read
~/.sharedcode/.env and /etc/environment as environment files.
User units stop when you log out unless lingering is enabled for your
account. That is a systemd setting, not a sharedcode one:
loginctl enable-linger "$USER".
Once a unit is installed, sharedcode gateway restart goes through
systemd. To stop a supervised service, use
systemctl --user stop <unit>. sharedcode telegram stop, for example,
refuses and tells you so, because Restart=always would bring the bot
straight back.
Health¶
sharedcode doctor --health
This probes the gateway, the upstream model endpoint, and the count of
open error records. It prints a table (see the
Quickstart) and exits non-zero
when a critical check is down, so it works as a liveness probe for
cron or a monitoring agent. It never makes a billable call. The one
check that does,
sharedcode doctor --bedrock-smoke, has to be asked for explicitly.
Without --health, sharedcode doctor works through the error records
in ~/.sharedcode/errors/. It asks an agent to fix each one on a new
errfix/<slug> git branch. Add --plan to approve a plan before any
edit.
Logs¶
Everything writes to ~/.sharedcode/logs/: gateway.log,
orchestrator.log, web.log, tui.log, and telegram.log and
heartbeat.log when those are in use. Follow them with:
sharedcode gateway logs
sharedcode web logs
sharedcode telegram logs
Under systemd, the gateway units also log to the journal
(journalctl --user -u sharedcode-gateway).
Sessions¶
Sessions are plain files, so maintenance is mostly reading:
sharedcode session list # recent sessions for the agent
sharedcode session show <session_id> # header and turns, folded from the JSONL
sharedcode session compact <session_id> # trim oversized tool results
sharedcode session rebuild # rebuild sessions.db from the JSONL files
sharedcode session delete <session_id>
If sessions.db is lost or damaged, rebuild recreates it from the
ledgers. The .jsonl files are the source of truth, and the database is a
cache.
Memory index¶
Normal maintenance is automatic. A write to memory is indexed straight
away, a search first indexes any drift it notices, and the gateway
heartbeat asks for a reindex only when one is needed. The Markdown memory
files are the source of truth; memory.db is a rebuildable index.
sharedcode memory status --agent jarvis # files, chunks, vectors, pending drift
sharedcode memory index --agent jarvis # incremental: changed files only
sharedcode memory index --agent jarvis --force # rebuild the index, keep cached embeddings
sharedcode memory index --agent jarvis --reembed # also re-call the embedding provider
Start with the incremental pass. --force never deletes memories, only
the derived index. --reembed is the expensive path for a changed
embedding model or a poisoned cache, and it needs a working embedding
provider.
Local vLLM router¶
sharedcode-vllm (the [vllm-router] extra) puts one OpenAI-compatible
address in front of several vLLM replicas. It does health checks, session
affinity, capacity admission and failover between replicas and pools,
and it can fall back to a hosted provider when every local option is down.
Its config is YAML, read from SHAREDCODE_VLLM_CONFIG or
vllm-router.yaml in the sharedcode home. The package ships a commented
template at sharedcode_vllm/data/vllm-router.example.yaml. A key in that
file is only ever the name of an environment variable; a literal
api_key is rejected.
This minimal config fronts one local vLLM server:
bind: 127.0.0.1
port: 8200
health_check_seconds: 5
pools:
qwen3.8-flash-next:
kind: llm
max_active_requests: 4
replicas:
- {name: gpu-a, url: http://127.0.0.1:8000, max_active: 4}
sharedcode-vllm --config router.yaml
A new replica only takes traffic after consecutive successful probes.
Until then /health reports it down and requests get HTTP 503 with a
retry_after. With the config above, the pool turned ok 40 seconds
after start:
$ curl -s http://127.0.0.1:8200/health
{"status":"ok","ok":["qwen3.8-flash-next"],"degraded":[],"down":[],"active_requests":{},"replicas":[{"pool":"qwen3.8-flash-next","name":"gpu-a","health":"ok","failure_class":"","consecutive_failures":0,"last_error":"","last_probe_age_s":4.608,"last_probe_latency_s":0.186,"cooldown_until":0.0}],"stuck_requests":0,"external_providers":[]}
Point sharedcode at the router (--endpoint http://127.0.0.1:8200/v1)
instead of at a single server. If you leave out bind and port, the
router listens on 0.0.0.0:8000, every interface, so set them.
SharedData worker pool¶
sharedcode_shareddata.workerpool dispatches commands to the worker pool
of a SharedData deployment (the shareddata data platform). A command
can run a routine on a named worker, or restart, stop or kill it.
It is a client only: you need a running SharedData server and a token
allowed to dispatch. The shareddata agent profile and the
shareddata-ops skill use the same client.
It needs two packages that no extra installs:
pip install pymongo lz4
Configuration comes from the environment, read on every call:
| Variable | Meaning |
|---|---|
SHAREDDATA_ENDPOINT |
The deployment's HTTP(S) base URL. Credentials, a query string or a fragment in the URL are refused. |
SHAREDDATA_COMMAND_TOKEN |
A command or master token. SHAREDDATA_TOKEN is used if this is unset. Worker and read-only tokens cannot dispatch. |
A command names the worker as user@COMPUTER and the routine as
Repo[/folder]/code, Repo#branch[/folder]/code or
SharedData.Module, without a .py suffix. The session below is real,
in the order it ran. The endpoint was a local test server that decodes
the command and answers HTTP 201, as a SharedData server does. It
received {'sender': 'MASTER', 'target': 'ops@worker-01', 'job':
'routine', 'repo': 'Reports', 'routine': 'jobs/nightly_summary.py',
'args': '--date 2026-10-20'}.
$ python -m sharedcode_shareddata.workerpool --computer ops@worker-01 --script Reports/jobs/nightly_summary
workerpool: Set SHAREDDATA_ENDPOINT to the deployment's HTTP(S) base URL.
$ export SHAREDDATA_ENDPOINT=http://127.0.0.1:18080 SHAREDDATA_COMMAND_TOKEN=stub-token
$ python -m sharedcode_shareddata.workerpool --computer ops@worker-01 --script Reports/jobs/nightly_summary --args="--date 2026-10-20"
Command queued (HTTP 201); inspect worker, schedule, and logs to verify execution.
$ python -m sharedcode_shareddata.workerpool --computer ops@worker-01 --script Reports/jobs/nightly_summary.py
workerpool: script must name a routine without a .py extension.
On an install without pymongo and lz4, the same command stops before
sending anything:
workerpool: Dispatch needs optional packages: install pymongo and lz4 in the runtime environment; do not install the unrelated bson package.
HTTP 201 means queued, not done. The client never retries, never
follows a redirect (that would hand the token to another host), and
never polls for the result. Check the worker, the schedule and the logs
before you send anything twice. From Python, dispatch(computer, script,
job, args) returns True on 201 and raises WorkerPoolError with a
message that is safe to show, never containing the token. Every failure
exits the CLI with code 2.