Files
MOPAC/deploy/harness.toml.in
T
mrcharles b7799ea0de deploy: 9-account/2-host packaging + static release build (Redmine 494)
Everything needed for one ~10-minute Charles window on ultix-streaming
and ultix-offstage, with zero root/systemd on the target accounts:

- deploy/accounts.tsv: the fleet authority (account, host, vertical,
  Redmine project, quota group, ports). Port scheme events=4100+index,
  serve=8090+index with a global 0-8 index so per-account daemons on
  one host never collide; loop state is per-account under ~/.mopac.
- deploy/install-account.sh <account>: idempotent installer run AS the
  target user; renders harness.toml from deploy/harness.toml.in, writes
  a 0600 env-secrets template, refuses to overwrite existing config or
  secrets (re-run = the upgrade path), generates mopac-start/stop.
- deploy/runbook.md: exact Charles sequence (build, stage, install,
  secrets bootstrap, verify, start via nohup or cron @reboot, rollback)
  with the account-port table, per-host time estimates and assumptions.
- Makefile: release target (digest-pinned docker builder, CGO off,
  linux/amd64 static, stripped) plus check/deploy-test entrypoints.
- deploy/tests.sh: 13 packaging tests (TSV scheme, template substitution
  for all 9 accounts, idempotence, refuse-to-overwrite, binary lookup,
  rendered config loads via a dry-run); README deploy section.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-08-29 05:50:41 -05:00

178 lines
5.4 KiB
Plaintext

# MOPAC harness configuration for @ACCOUNT@ (@HOST@, index @INDEX@) —
# generated by deploy/install-account.sh from deploy/accounts.tsv
# (Redmine 494). Hand-edits are ALLOWED and survive re-runs of the
# installer (it refuses to overwrite an existing harness.toml).
#
# No secrets in this file, ever — only env: refs resolved at runtime from
# ~/.mopac/env (0600, see deploy/runbook.md bootstrap step).
# Vertical / stack identity for this harness instance.
vertical = "@VERTICAL@"
# Absolute paths (substituted at install): the bash tool executes in
# work_root; REPORTs land in report_dir; daemons keep state under state/.
work_root = "@HOME@/.mopac/work"
report_dir = "@HOME@/.mopac/reports"
[loop]
# Bounded turn: max LLM round trips per task (tool calls included).
max_rounds = 8
# `harness loop` daemon: Redmine scan interval and state location
# (append-only loop.jsonl, dedup by issue id + updated_on).
poll_interval_secs = 120
state_dir = "@HOME@/.mopac/state/loop"
[redmine]
url = "https://projects.knownelement.com"
key_ref = "env:HARNESS_REDMINE_KEY"
# Released scope for this account's vertical (project from accounts.tsv):
scope_query = "project=@REDMINE_PROJECT@&status_id=released&limit=25"
# class_field: Redmine custom field carrying the TASK class; issues
# without it get default_class.
class_field = "Class"
default_class = "primary"
# After a REPORT is noted back on an issue, an issue whose CURRENT status
# matches a key here moves to the value (names resolved via
# /issue_statuses.json). Set the pair that moves work OUT of the released
# scope for this project's workflow, e.g. (uncomment + adjust names):
# [redmine.status_map]
# "Released" = "Done"
# Empty/absent map = leave status alone (the loop still advances its own
# dedup marker past its writebacks — no redispatch storm).
[litellm]
base_url = "http://192.168.3.78:4001"
key_ref = "env:HARNESS_LITELLM_KEY"
timeout_secs = 120
max_retries = 2
# GITEA (optional, off by default): `harness loop` commits each REPORT
# file to this repo right after writing it. Per-account REPORT repos can
# be wired later by uncommenting (key goes into ~/.mopac/env).
# [gitea]
# url = "https://git.knownelement.com"
# key_ref = "env:HARNESS_GITEA_KEY"
# owner = "ukrrs"
# repo = "MOPAC-reports"
# branch = "main"
# commit_reports = false
# MODEL ROUTING v0 (static, config-only): [models] is the tier map (tier
# alias -> concrete proxy model); [models.classes] maps task classes to
# tiers. Swapping models is a one-line edit here.
[models]
mopac-study = "glm-4.7-flash" # flash tier
mopac-code = "glm-5.2" # flagship
mopac-review = "glm-5-turbo" # mid
mopac-primary = "glm-5.3" # default / flagship+
mopac-vision = "glm-4.6v" # vision when needed
default_tier = "mopac-primary"
[models.classes]
study = "mopac-study"
read = "mopac-study"
code = "mopac-code"
architecture = "mopac-code"
review = "mopac-review"
summarize = "mopac-review"
writeback = "mopac-review"
vision = "mopac-vision"
primary = "mopac-primary"
# Exec tool: allow-listed bash. Org preset: deny-first, read-leaning allow
# list, no sudo/ssh/network exfil.
[tools.bash]
enabled = true
timeout_secs = 60
max_output_bytes = 100000
default = "deny"
deny = [
"sudo *",
"ssh *",
"scp *",
"nc *",
"curl *",
"wget *",
"rm -rf *",
]
allow = [
"pwd",
"ls *",
"cat *",
"head *",
"tail *",
"grep *",
"find *",
"wc *",
"echo *",
"env",
"git status",
"git diff *",
"git log *",
"git show *",
"go version",
"go build *",
"go vet *",
"go test *",
]
# Smoke-test issue for this install: `harness once --dry-run --demo` runs
# the plan path with NO secrets and NO LLM call — the runbook verify step.
[demo]
id = "demo-@VERTICAL@"
subject = "@ACCOUNT@ install smoke"
prompt = "introduce yourself and your vertical"
class = "primary"
# EVENTS: the `harness events` webhook receiver. Port @EVENTS_PORT@ =
# 4100 + index from accounts.tsv — unique per account per host.
[events]
listen = ":@EVENTS_PORT@"
state_dir = "@HOME@/.mopac/state/events"
[events.redmine]
secret_ref = "env:HARNESS_REDMINE_WEBHOOK_SECRET"
[events.discourse]
secret_ref = "env:HARNESS_DISCOURSE_WEBHOOK_SECRET"
[events.gitea]
secret_ref = "env:HARNESS_GITEA_WEBHOOK_SECRET"
# SERVE: the OpenAI-compatible front door for OpenWebUI. Port
# @SERVE_PORT@ = 8090 + index from accounts.tsv. Bearer vkey auth — the
# same value goes into the OWUI connection config for this account.
[serve]
listen = ":@SERVE_PORT@"
vkey_ref = "env:HARNESS_SERVE_VKEY"
# QUOTA GATE (Redmine 490): values pre-filled for this account's plan
# group (@QUOTA_ACCOUNT@); flip enabled = true once the shared redis
# container is up (README runbook) and the grouping is confirmed.
# [quota]
# enabled = false
# account = "@QUOTA_ACCOUNT@"
# plan_5h_credits = 28000
# plan_weekly_credits = 140000
# usage_url = ""
# key_ref = "env:HARNESS_ZAI_KEY"
# poll_interval_secs = 300
# defer_at_pct = 85
# block_at_pct = 95
# peak_start = "01:00"
# peak_end = "05:00"
# timezone = "America/Chicago"
# peak_weekdays_only = true
# peak_classes = ["study", "read"]
# redis_url = "redis://192.168.3.78:6390/0"
# RESOURCE GATE (Redmine 491): read-only host monitor; the loop defers
# dispatch while busy. Flip enabled = true per host capacity.
# [resources]
# enabled = false
# max_load_avg = 6.0
# min_mem_available_mb = 2048
# min_disk_free_mb = 5120
# max_io_delay_pct = 90.0