Files
tireless/asset/systemd/tireless-runner.service
rob thijssen 4e42f87576
Some checks failed
deploy / build (push) Has been cancelled
deploy / deploy (push) Has been cancelled
feat(tireless): scaffold workspace, dashboard and staged design plan
Autonomous issue-to-PR driver for Claude Code and OpenCode, structured per
lair/architecture generic.md.

Workspace: entities/core/data/agent library crates plus api, worker and cli
binaries. Two pieces of real logic land with tests — lane routing (cc for
judgement, oc for specification) and the limit governor.

Constraints encoded as code rather than comments:
- agents are spawned as vendor binaries; tireless never calls a provider API
- ANTHROPIC_API_KEY is never set by tireless, only passed through
- assert_not_anthropic refuses to start an OpenCode lane pointed at Anthropic
- every run passes the governor; provider rate-limit signals win over our own
  accounting

Deployment assets target bob.hanzalova.internal:23296 (registered in
port-allocations.md), fronted by hanzalova at tireless.internal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHhHtohxcdk1PL3tfnYJdH
2026-08-02 12:46:42 +03:00

66 lines
2.4 KiB
Desktop File

[Unit]
Description=tireless job runner (drives Claude Code and OpenCode)
Documentation=https://git.lair.cafe/lair/tireless
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=tireless
Group=tireless
# Claude Code and OpenCode both keep credentials and caches under HOME. The
# service account's home is its state directory, and it must be writable: the
# subscription OAuth token is refreshed in place, so a read-only HOME breaks
# authentication after the first expiry rather than at startup.
Environment=HOME=/var/lib/tireless
Environment=NPM_CONFIG_LOGLEVEL=error
Environment=NODE_NO_WARNINGS=1
# Optional secrets, 0640 root:tireless, never in source control:
# GITEA_TOKEN=… token for the dedicated `tireless` bot account
# GITHUB_TOKEN=… only for legacy GitHub repos
# ANTHROPIC_API_KEY=… OPTIONAL. Present -> Claude Code bills pay-as-you-go.
# Absent -> Claude Code uses the subscription login
# stored in /var/lib/tireless/.claude.json.
# tireless never sets this variable itself; the choice is the operator's, and
# the runner logs which mode is active at startup.
EnvironmentFile=-/etc/tireless/tireless.env
ExecStart=/usr/local/bin/tireless-worker --config /etc/tireless/config.toml run
Restart=on-failure
RestartSec=30s
# Give in-flight agent runs time to be cancelled cleanly, then kill the whole
# process group — npx-spawned agents leave orphans otherwise.
TimeoutStopSec=120
KillMode=control-group
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
SystemCallArchitectures=native
# RELAXATION, deliberate: MemoryDenyWriteExecute=true is omitted here (it is set
# on tireless-api and tireless-poller). Both agents are Node programs, and V8's
# JIT requires write-then-execute pages; with it enabled the agent aborts on
# startup. Per §8 we relax only the one setting that breaks the service.
MemoryDenyWriteExecute=false
# The runner clones repos, runs builds and spawns agents, all under its state
# directory. PrivateTmp gives it an isolated /tmp for the toolchains that insist
# on one.
ReadWritePaths=/var/lib/tireless
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
[Install]
WantedBy=multi-user.target