Skip to content

Latest commit

 

History

History
287 lines (221 loc) · 9.03 KB

agent-configuration.md

File metadata and controls

287 lines (221 loc) · 9.03 KB

Agent Configuration

How to point your coding agents at AuditTrace-AI.

Prerequisites

  1. Stack is running: ./scripts/start-full-stack.sh
  2. mkcert CA is installed locally: mkcert -install (already run during cert generation)

Endpoint changes

Legacy Current
http://localhost:8765/v1/chat/completions https://localhost/v1/chat/completions
http://localhost:8765/invoke https://localhost/context (POST {"query": "..."})
http://localhost:8765/health https://localhost/health

The mkcert CA is trusted system-wide, so HTTPS works without -k for tools that read the system trust store. Some tools bundle their own — see notes per agent.


OpenCode

File: ~/.config/opencode/config.json

Since ADR-026 Phase 5b the memory-server defaults to AUDITTRACE_AUTH_REQUIRED=true, which means every request must carry a valid Keycloak JWT in the Authorization: Bearer header. The @ai-sdk/openai-compatible provider maps its apiKey field to exactly that header, so we reuse it as the JWT carrier.

Step 1 — mint a dev JWT (valid 10h)

Use the sovereign-memory-dev client via the helper script:

# One-time setup: copy script + read the secret
docker cp scripts/mint-dev-jwt.sh audittrace-ai:/tmp/
TOKEN=$(docker exec \
    -e CLIENT_SECRET="$(cat secrets/dev_client_secret.txt)" \
    audittrace-ai bash /tmp/mint-dev-jwt.sh)
echo "$TOKEN" > ~/.config/opencode/sovereign-jwt.txt

The token lasts ~10 hours (client-level access.token.lifespan=86400 is capped by the realm's default SSO session max of 10h). Re-mint once per workday.

Why not Traefik HTTPS + apiKey from the host? Keycloak's issuer is http://keycloak:8080/realms/sovereign-ai (the internal docker-network hostname the memory-server trusts). Running the mint script from inside the audittrace-net via docker exec guarantees the JWT's iss claim matches what require_user validates. A host-side mint against localhost or Traefik would produce a token with a different issuer that the memory-server would reject.

Step 2 — plug the token into OpenCode

{
  "$schema": "https://opencode.ai/config.json",
  "model": "sovereign/qwen3.8",
  "provider": {
    "sovereign": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "audittrace-ai",
      "options": {
        "baseURL": "https://localhost/v1",
        "apiKey": "<paste the JWT from sovereign-jwt.txt here>",
        "headers": {
          "X-Project": "default"
        }
      },
      "models": {
        "qwen3.8": {
          "name": "Qwen3.8-27B (dense) + MTP",
          "tools": true
        }
      }
    }
  },
  "instructions": ["~/.config/opencode/AGENTS.md"]
}

Step 3 — tag each OpenCode session with a project (ADR-029)

Without an X-Project header every interaction lands with project="default" — recall_recent_sessions then has no way to scope cross-session memory to the project you're actually working on. The memory-server reads the header on every /v1/chat/completions, falls back to body.metadata.project, then body.project, then "default".

One helper script ships with the server to set the tag without editing JSON by hand:

# Before starting a new project session
scripts/configure-project.py AuditTrace-AI

# Preview without writing
scripts/configure-project.py SMC --dry-run

# Inspect the current value per provider
scripts/configure-project.py --show

# Set the tag AND launch opencode in one go
scripts/configure-project.py SMC --launch

The script walks every provider.*.options block in ~/.config/opencode/config.json and sets headers["X-Project"] = <name>. A timestamped backup is written alongside the config; the new file replaces the old atomically (os.replace), so a partial write cannot leave the config broken.

Restart OpenCode after running the script — it reads config at launch, so a session that is already open is still using the old header.

A single-line refresh wrapper (optional, nicer DX) — save as ~/.config/opencode/refresh-jwt.sh:

#!/usr/bin/env bash
set -euo pipefail
REPO="${1:-$HOME/work/AuditTrace-AI}"
cd "$REPO"
docker cp scripts/mint-dev-jwt.sh audittrace-ai:/tmp/ >/dev/null
TOKEN=$(docker exec -e CLIENT_SECRET="$(cat secrets/dev_client_secret.txt)" \
    audittrace-ai bash /tmp/mint-dev-jwt.sh)
# Patch the apiKey in OpenCode's config in place (requires jq)
CONF=~/.config/opencode/config.json
tmp=$(mktemp)
jq --arg t "$TOKEN" \
   '.provider.sovereign.options.apiKey = $t' \
   "$CONF" > "$tmp" && mv "$tmp" "$CONF"
echo "Refreshed OpenCode JWT (sub: $(echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq -r .sub))"

Run once per day (or hook into your shell's session start).

Step 3 — TLS trust for Node

If you hit self signed certificate in certificate chain, set NODE_EXTRA_CA_CERTS before launching OpenCode:

export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
opencode

Add this to your ~/.zshrc to make it permanent.

Bypass mode (emergency)

If Keycloak is down or you need to debug without auth, flip the memory-server env back to AUDITTRACE_AUTH_REQUIRED=false for the duration of the debug session:

# k3s + Helm is the sole app-deploy path (docker-compose was stopped).
# Toggle the flag on the running Deployment and roll it:
kubectl set env deploy/audittrace-memory-server AUDITTRACE_AUTH_REQUIRED=false
kubectl rollout status deploy/audittrace-memory-server
# Durable change: set memoryServer env in charts/audittrace/values.yaml + helm upgrade.

The sentinel UserContext takes over and requests without JWTs get the admin-by-construction fallback. Flip back to true when done (kubectl set env deploy/audittrace-memory-server AUDITTRACE_AUTH_REQUIRED=true).


Continue (VS Code extension)

File: ~/.continue/config.yaml

name: Sovereign Memory Server
version: 1.0.0
schema: v1

models:
  - name: Qwen3.8-27B dense+MTP (sovereign)
    provider: openai
    model: qwen3.8
    apiBase: https://localhost/v1
    apiKey: dummy
    contextLength: 65536
    defaultCompletionOptions:
      temperature: 0.7
      maxTokens: 4096

tabAutocompleteModel:
  name: Qwen3.8-27B dense+MTP (sovereign)
  provider: openai
  model: qwen3.8
  apiBase: https://localhost/v1
  apiKey: dummy

# Memory context injection — calls /context before each query
contextProviders:
  - name: http
    params:
      url: https://localhost/context
      title: "Sovereign Memory"
      description: "five-layer memory — sessions, ADRs, skills, semantic RAG, shared corpus"
      displayTitle: "Memory"

systemMessage: |
  You are working with a Solutions Architect specialized in IAM/OAuth2.
  Local stack: llama-server :11435 (Qwen3.8-27B dense+MTP, Vulkan).
  Memory server: audittrace-ai (five-layer memory, PostgreSQL + ChromaDB).
  Always answer in English.

Continue uses Node's HTTPS stack and respects the system CA store on Linux. If TLS errors persist, set NODE_EXTRA_CA_CERTS in your VS Code launcher.


Roo Code (VS Code extension)

Settings → Roo Code → API Configuration:

Field Value
API Provider OpenAI Compatible
Base URL https://localhost/v1
API Key dummy
Model qwen3.8
Custom Headers (none)

If TLS errors appear, launch VS Code with:

NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" code .

Verification

After updating any agent, test with a simple query:

curl -s https://localhost/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3.8","messages":[{"role":"user","content":"What is ADR-009 about?"}]}' \
  | python3 -m json.tool

If memory augmentation works, the answer should reference KV cache compression (content from your migrated ADR-009 file).


Authentication (ADR-022, ADR-023, ADR-026)

Current default since ADR-026 Phase 5b: AUDITTRACE_AUTH_REQUIRED=true — every request needs a valid Keycloak JWT in Authorization: Bearer <jwt>. See the per-agent sections above for how to plug a token into each client.

Two auth flags exist:

Flag Purpose Default
AUDITTRACE_AUTH_ENABLED Legacy require_scope gate (ADR-022, ADR-023). Gates specific scope strings per route false
AUDITTRACE_AUTH_REQUIRED New require_user gate (ADR-026 §15). Validates JWT against JWKS, populates UserContext, pushes app.current_user_id into Postgres RLS true

The two are independent but today both live on the memory-server; require_user is the authoritative path for per-user identity.

JWT sources:

Client type Flow Client
Dev / curl / Bruno client_credentials grant with a service account sovereign-memory-dev
OpenCode / Continue / Roo Code (daily use) Client-credentials JWT via scripts/mint-dev-jwt.sh, paste into client config Same as above
Production humans OAuth2 device flow (deferred — Phase 8+) Dedicated public client TBD

See ADR-026 §15 for the full Keycloak-delegated identity design and §16 for the end-of-2026-04-11 shipped status with commit SHAs.