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
178 lines
5.4 KiB
Plaintext
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
|