Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

qm-config

Private local-dev configuration for running QM as a full stack on this machine — core (with the in-process Slack bot) plus the web, admin, and portal surfaces, backed by Postgres.

This repo holds only configuration and scripts. The QM source (core) is a separate checkout at $QM_DIR and is not stored here. No real secret ever lands in git — everything sensitive lives in the gitignored .env.

Layout

.env.example         # template; copied to .env by setup.sh
.env                 # real config + secrets (gitignored)
docker-compose.yml   # local Postgres (qm-pg)
scripts/
  setup.sh           # one-time: .env + secrets, Postgres, deps, web-ui build
  up.sh              # boot core + web + admin + portal
  down.sh            # stop them (--pg also stops Postgres)
  logs.sh            # tail logs
  build-sandbox.sh   # build the local Docker sandbox image (slow, optional)
  lib.sh             # shared env loading + Node 24 on PATH
deploy/layers/hbd/   # placeholder for a future real Fly/AWS deploy layer

Prerequisites

  • Node ≥ 24brew install node@24 (scripts put it on PATH automatically)
  • Docker running (Postgres + the agent sandbox)
  • An ANTHROPIC_API_KEY (default model is claude-opus-5; the claude harness is Anthropic-only)

Quick start

# 1. Clone the QM core next to this repo (once)
git clone https://github.com/yc-software/qm ../qm      # -> $QM_DIR

# 2. Setup: creates .env, generates secrets, starts Postgres, installs deps
scripts/setup.sh

# 3. Put your key in .env
#    ANTHROPIC_API_KEY=sk-ant-...

# 4. Boot the stack
scripts/up.sh

Then open http://localhost:8088 (the portal front door). On localhost the portal signs you in automatically as DEV_ADMIN_PRINCIPAL (no email login). Admin is at http://localhost:8088/admin.

Using both pi and claude

HARNESS=pi in .env is the org default. To make both selectable per person/room:

  1. Open /admin → the runtime/harness governance card.
  2. Set approved harnesses to pi and claude.
  3. In the Web UI each scope can then pick pi or claude (and its model); Slack uses whatever that scope resolves to.

Quick alternative for a one-off test: set HARNESS=claude in .env and restart (scripts/down.sh && scripts/up.sh).

Local model: llama.cpp / Qwen (pi harness)

patches/0001-pi-qwen-local.patch (applied to the core by setup.sh via scripts/apply-patches.sh) registers a selectable model id qwen-local that the pi harness calls over the OpenAI-compatible chat-completions API — no translation proxy. Verified working end-to-end (generation and tool calls) against Qwen3.6-35B-A3B-local.

Requirements & config (.env):

  • llama.cpp serving on LLAMACPP_BASE_URL (default http://127.0.0.1:8888/v1), started with tool support (--jinja + a tool-capable chat template) so the agent's tool calls work.
  • OPENROUTER_API_KEY set to any placeholder — pi needs a key in the model's provider slot; llama.cpp ignores it.
  • Optional PI_MODEL=qwen-local to make it the default model (needed for a local-only run with no Anthropic key). Otherwise Claude stays default and you pick qwen-local per-scope in the Web UI.

Recommended llama.cpp server flags (latency)

Start llama-server with a tool-capable chat template and thinking disabled. Qwen3.6 otherwise emits a long reasoning trace before every answer (~300 tokens/turn) that dominates local latency and bloats the stored history — --reasoning-budget 0 alone does not stop it; use --chat-template-kwargs:

llama-server --model <Qwen3.6-35B-A3B-…-.gguf> --alias Qwen3.6-35B-A3B-local \
  --host 127.0.0.1 --port 8888 -ngl 99 --flash-attn on --mlock \
  -c 131072 -b 2048 -ub 2048 --cache-type-k q8_0 --cache-type-v q4_0 \
  --cache-ram 4096 --ctx-checkpoints 24 \
  --jinja --chat-template-kwargs '{"enable_thinking":false}' \
  --parallel 1 --spec-draft-n-max 6 --spec-type draft-mtp,ngram-mod \
  --override-kv qwen35moe.expert_used_count=int:6

With this plus patches/0002-pi-stable-cwd.patch, warm turns run ~1–3s: llama.cpp reuses the whole KV prefix and only the new message is prefilled. The first turn of a session is still a cold full prefill (~30s).

Switching between models

qwen-local shows up alongside the Claude/GPT models. Switch by:

  • Web UI model picker (per person/room) — pick qwen-local or a claude-* model. This is the normal, live way; Slack follows the scope's selection.
  • /admin — set the org base model, the Web-UI model list, or approved harnesses.
  • .envPI_MODEL=qwen-local sets the pi default; unset it (or set a claude-* id) to default back. Restart after editing.

Note: qwen-local runs only under the pi harness. Caveats: the first turn of a session is slow (cold prefill of the ~6–7k-token system prompt + tools), and tool-calling quality depends on the model. Heavy local-only use can skip the inbound content classifier with HARNESS_SECURITY_POSTURE=dangerous (dev only — it otherwise also runs on the local model). See the server-flags block above for the latency-critical settings; aux calls (title/memory) run on the local model too as long as no Anthropic-provider base model is set (keep the org base unset or qwen-local).

To update these customizations, edit the core and regenerate the affected patch, e.g. git -C ../qm diff -- src/model/pi-models.ts > patches/0001-pi-qwen-local.patch or git -C ../qm diff -- src/harness/pi-harness.ts > patches/0002-pi-stable-cwd.patch, then commit it here.

Connect Slack

Slack runs in-process with core — set the two tokens and restart, no public URL needed (Socket Mode).

  1. api.slack.com/apps → Create New App → From an app manifest → your workspace. Paste $QM_DIR/cli/templates/slack-manifest.json (Socket Mode on, all needed scopes/events already declared).
  2. Install to Workspace → copy the Bot User OAuth Token (xoxb-…).
  3. Basic Information → App-Level Tokens → create one with scope connections:write → that is the xapp-….
  4. Put both in .env:
    SLACK_BOT_TOKEN=xoxb-...
    SLACK_APP_TOKEN=xapp-...
    
  5. scripts/down.sh && scripts/up.sh. Invite the bot to a channel and @-mention it, or DM it. (DM = your personal scope; channel = a shared scope.)

The agent sandbox

The agent's execute tool runs commands in a per-scope Docker sandbox. Build the image once (slow under Apple-Silicon emulation):

scripts/build-sandbox.sh

Until it exists, everything works except execute turns.

Durability

Session/run state is in Postgres (qm-pg), so it survives restarts. down.sh leaves Postgres running; down.sh --pg stops it too. Data persists in the qm-pgdata Docker volume.

About

Local model optimized config for qm - the multiplayer agent harness for work

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages