Oppdater docs og config for native maskinrommet + Claude-agent
- CLAUDE.md: ny driftsmodell-seksjon, maskinrommet native, Claude-agent - docs/infra/claude_agent.md: arkitektur, sikkerhet, drift, oppsett - config/caddy/Caddyfile: synk fra server (host.docker.internal) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
33a1b44946
commit
1dd48317af
3 changed files with 154 additions and 12 deletions
18
CLAUDE.md
18
CLAUDE.md
|
|
@ -56,6 +56,7 @@ CLAUDE.md er eneste startdokument. Alt annet ligger under `docs/`:
|
||||||
- `api_grensesnitt.md` — Kommunikasjonskart: SvelteKit er web-API, Rust er worker
|
- `api_grensesnitt.md` — Kommunikasjonskart: SvelteKit er web-API, Rust er worker
|
||||||
- `jobbkø.md` — PostgreSQL-basert køsystem for bakgrunnsjobber
|
- `jobbkø.md` — PostgreSQL-basert køsystem for bakgrunnsjobber
|
||||||
- `synkronisering.md` — PostgreSQL ↔ SpacetimeDB dataflyt og eierskapsmodell
|
- `synkronisering.md` — PostgreSQL ↔ SpacetimeDB dataflyt og eierskapsmodell
|
||||||
|
- `claude_agent.md` — Claude som chat-deltaker: arkitektur, triggere, sikkerhet
|
||||||
- `docs/erfaringer/` — Lærdommer fra v1 (adapter-mønster, Svelte 5, SpacetimeDB, Authentik)
|
- `docs/erfaringer/` — Lærdommer fra v1 (adapter-mønster, Svelte 5, SpacetimeDB, Authentik)
|
||||||
- `reference/` — Kode fra v1 med gjenbruksverdi (Editor.svelte)
|
- `reference/` — Kode fra v1 med gjenbruksverdi (Editor.svelte)
|
||||||
- `ops/` — Repeterbare vedlikeholdsjobber (ryddejobb, doc-audit, drift-sjekk)
|
- `ops/` — Repeterbare vedlikeholdsjobber (ryddejobb, doc-audit, drift-sjekk)
|
||||||
|
|
@ -66,13 +67,24 @@ CLAUDE.md er eneste startdokument. Alt annet ligger under `docs/`:
|
||||||
- Begge har sudo + docker-tilgang på serveren.
|
- Begge har sudo + docker-tilgang på serveren.
|
||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
- **Orkestrator/Backend:** Rust (maskinrommet)
|
- **Orkestrator/Backend:** Rust (maskinrommet) — kjører native på hosten
|
||||||
- **Frontend:** SvelteKit (TypeScript, PWA)
|
- **Frontend:** SvelteKit (TypeScript, PWA)
|
||||||
- **Sanntid:** SpacetimeDB
|
- **Sanntid:** SpacetimeDB
|
||||||
- **Database/Graf:** PostgreSQL (+Apache AGE ved behov)
|
- **Database/Graf:** PostgreSQL (+Apache AGE ved behov)
|
||||||
- **Binærlagring:** CAS (content-addressable store)
|
- **Binærlagring:** CAS (content-addressable store)
|
||||||
- **AI:** LiteLLM (AI Gateway), faster-whisper (STT), ElevenLabs (TTS)
|
- **AI:** Claude Code (chat-agent), LiteLLM (AI Gateway), faster-whisper (STT)
|
||||||
- **Infra:** Docker Compose, Caddy, Authentik (SSO)
|
- **Infra:** Docker Compose, Caddy, Authentik (SSO), systemd
|
||||||
|
|
||||||
|
## Driftsmodell
|
||||||
|
- **Maskinrommet** kjører direkte på hosten som systemd-tjeneste (`maskinrommet.service`),
|
||||||
|
ikke i Docker. Dette gir tilgang til `claude` CLI for agent-chat.
|
||||||
|
Bygges med `cargo build --release`, startes med `sudo systemctl restart maskinrommet`.
|
||||||
|
- **Øvrige tjenester** (PG, STDB, Caddy, Authentik, Whisper, LiteLLM) kjører i Docker.
|
||||||
|
- **Caddy** bruker `host.docker.internal` for å nå maskinrommet på hosten.
|
||||||
|
- **Claude som chat-deltaker:** Agent-node (`d3eebc99-...-a44`) i grafen. Legg Claude
|
||||||
|
til som `member_of` i en kommunikasjonsnode → alle meldinger trigger `agent_respond`-jobb
|
||||||
|
→ maskinrommet kaller `claude -p` → svar skrives tilbake i chatten.
|
||||||
|
- **Kill switch:** `UPDATE agent_identities SET is_active = false WHERE agent_key = 'claude-main'`
|
||||||
|
|
||||||
## Produksjonsserver
|
## Produksjonsserver
|
||||||
- **IP:** 157.180.81.26
|
- **IP:** 157.180.81.26
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,22 @@
|
||||||
# Alt annet rutes internt via Docker-nettverket sidelinja-net.
|
# Alt annet rutes internt via Docker-nettverket sidelinja-net.
|
||||||
# Auto-TLS via Let's Encrypt for alle domener.
|
# Auto-TLS via Let's Encrypt for alle domener.
|
||||||
|
|
||||||
|
# === Felles favicon-snippet ===
|
||||||
|
(favicon) {
|
||||||
|
handle /favicon.ico {
|
||||||
|
root * /srv/static
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
handle /apple-touch-icon.png {
|
||||||
|
root * /srv/static
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
handle /icon-*.png {
|
||||||
|
root * /srv/static
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# === SSO ===
|
# === SSO ===
|
||||||
auth.sidelinja.org {
|
auth.sidelinja.org {
|
||||||
reverse_proxy authentik-server:9000
|
reverse_proxy authentik-server:9000
|
||||||
|
|
@ -11,6 +27,8 @@ auth.sidelinja.org {
|
||||||
|
|
||||||
# === Sidelinja (hovedapplikasjon) ===
|
# === Sidelinja (hovedapplikasjon) ===
|
||||||
sidelinja.org {
|
sidelinja.org {
|
||||||
|
import favicon
|
||||||
|
|
||||||
# SpacetimeDB (WebSocket)
|
# SpacetimeDB (WebSocket)
|
||||||
handle_path /spacetime/* {
|
handle_path /spacetime/* {
|
||||||
reverse_proxy spacetimedb:3000
|
reverse_proxy spacetimedb:3000
|
||||||
|
|
@ -28,18 +46,13 @@ sidelinja.org {
|
||||||
# Aktiveres når SvelteKit-containeren er klar (fase 3)
|
# Aktiveres når SvelteKit-containeren er klar (fase 3)
|
||||||
# reverse_proxy sveltekit:3000
|
# reverse_proxy sveltekit:3000
|
||||||
|
|
||||||
# Placeholder til SvelteKit er deployet
|
header Content-Type text/html
|
||||||
respond "sidelinja.org — Synops v2 under utvikling" 200
|
respond `<!DOCTYPE html><html><head><meta charset="utf-8"><title>sidelinja.org</title><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192"><link rel="apple-touch-icon" href="/apple-touch-icon.png"></head><body><p>sidelinja.org — underveis!</p></body></html>` 200
|
||||||
}
|
}
|
||||||
|
|
||||||
# === Maskinrommet API ===
|
# === Maskinrommet API ===
|
||||||
api.sidelinja.org {
|
api.sidelinja.org {
|
||||||
# Rust/axum backend (fase 2)
|
reverse_proxy host.docker.internal:3100
|
||||||
# Aktiveres når maskinrommet-containeren er klar
|
|
||||||
# reverse_proxy maskinrommet:3001
|
|
||||||
|
|
||||||
# Placeholder til maskinrommet er deployet
|
|
||||||
respond "api.sidelinja.org — ikke tilgjengelig ennå" 503
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# === Forgejo (Git) ===
|
# === Forgejo (Git) ===
|
||||||
|
|
@ -47,7 +60,20 @@ git.sidelinja.org {
|
||||||
reverse_proxy forgejo:3000
|
reverse_proxy forgejo:3000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# === Synops (plattformdomene) ===
|
||||||
|
# Subdomener (api.synops.no, auth.synops.no osv.) legges til individuelt
|
||||||
|
# etter behov — HTTP-challenge fungerer per subdomain uten DNS-plugin.
|
||||||
|
synops.no {
|
||||||
|
import favicon
|
||||||
|
|
||||||
|
header Content-Type text/html
|
||||||
|
respond `<!DOCTYPE html><html><head><meta charset="utf-8"><title>synops.no</title><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192"><link rel="apple-touch-icon" href="/apple-touch-icon.png"></head><body><p>synops.no — underveis!</p></body></html>` 200
|
||||||
|
}
|
||||||
|
|
||||||
# === Vegard.info ===
|
# === Vegard.info ===
|
||||||
vegard.info {
|
vegard.info {
|
||||||
respond "vegard.info — under construction" 200
|
import favicon
|
||||||
|
|
||||||
|
header Content-Type text/html
|
||||||
|
respond `<!DOCTYPE html><html><head><meta charset="utf-8"><title>vegard.info</title><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192"><link rel="apple-touch-icon" href="/apple-touch-icon.png"></head><body><p>vegard.info — underveis!</p></body></html>` 200
|
||||||
}
|
}
|
||||||
|
|
|
||||||
104
docs/infra/claude_agent.md
Normal file
104
docs/infra/claude_agent.md
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Infrastruktur: Claude som chat-deltaker
|
||||||
|
|
||||||
|
## Oversikt
|
||||||
|
|
||||||
|
Claude deltar i samtaler som en agent-node i grafen. Når en bruker sender
|
||||||
|
en melding i en kommunikasjonsnode der Claude er deltaker, trigger maskinrommet
|
||||||
|
en `agent_respond`-jobb som kaller `claude -p` CLI og skriver svaret tilbake.
|
||||||
|
|
||||||
|
## Arkitektur
|
||||||
|
|
||||||
|
```
|
||||||
|
Bruker sender melding (via frontend)
|
||||||
|
→ create_node() i maskinrommet
|
||||||
|
→ sjekker: har kommunikasjonsnoden en agent-deltaker?
|
||||||
|
→ ja: enqueue agent_respond-jobb (prioritet 8)
|
||||||
|
→ jobbkø-worker plukker opp (poll hvert 2s)
|
||||||
|
→ kaller: claude -p "<prompt>" --output-format json --dangerously-skip-permissions
|
||||||
|
→ parser JSON-respons, henter result-feltet
|
||||||
|
→ skriver svar som content-node (STDB instant + PG async)
|
||||||
|
→ frontend viser melding i sanntid via STDB WebSocket
|
||||||
|
```
|
||||||
|
|
||||||
|
Latens: ~3-5 sekunder fra melding til svar.
|
||||||
|
|
||||||
|
## Noder og tabeller
|
||||||
|
|
||||||
|
### Claude-noden
|
||||||
|
- **UUID:** `d3eebc99-9c0b-4ef8-bb6d-6bb9bd380a44`
|
||||||
|
- **node_kind:** `agent`
|
||||||
|
- **visibility:** `discoverable`
|
||||||
|
|
||||||
|
### agent_identities
|
||||||
|
Kobler agent-noder til konfigurasjon og nøkkel.
|
||||||
|
|
||||||
|
| Felt | Verdi |
|
||||||
|
|------|-------|
|
||||||
|
| agent_key | `claude-main` |
|
||||||
|
| agent_type | `claude` |
|
||||||
|
| config | max_context_messages, rate_limit_per_hour, etc. |
|
||||||
|
|
||||||
|
### agent_permissions
|
||||||
|
Autorisasjonsnivåer per bruker/agent-par.
|
||||||
|
|
||||||
|
| Nivå | Betydning |
|
||||||
|
|------|-----------|
|
||||||
|
| `direct` | Kan bestille endringer som implementeres direkte |
|
||||||
|
| `propose` | Kan foreslå endringer som krever godkjenning |
|
||||||
|
|
||||||
|
### ai_usage_log
|
||||||
|
Logger hvert agent-svar med timestamps, job_id, og kommunikasjons-ID.
|
||||||
|
|
||||||
|
## Sikkerhet
|
||||||
|
|
||||||
|
| Mekanisme | Beskrivelse |
|
||||||
|
|-----------|-------------|
|
||||||
|
| **Kill switch** | `agent_identities.is_active = false` stopper all aktivitet |
|
||||||
|
| **Rate limiting** | Maks 60 responser per time (konfigurerbart) |
|
||||||
|
| **Loop-prevensjon** | Stopper hvis siste 3 meldinger er fra agenten |
|
||||||
|
| **Egne meldinger** | Svarer aldri på egne meldinger (sjekk i trigger) |
|
||||||
|
|
||||||
|
## Oppsett av ny chat med Claude
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. Opprett kommunikasjonsnode
|
||||||
|
INSERT INTO nodes (id, node_kind, title, visibility, metadata, created_by)
|
||||||
|
VALUES ('<uuid>', 'communication', 'Min chat med Claude', 'hidden', '{}', '<bruker-uuid>');
|
||||||
|
|
||||||
|
-- 2. Legg til bruker som owner
|
||||||
|
INSERT INTO edges (id, source_id, target_id, edge_type, metadata, system, created_by)
|
||||||
|
VALUES ('<uuid>', '<bruker-uuid>', '<comm-uuid>', 'owner', '{}', false, '<bruker-uuid>');
|
||||||
|
|
||||||
|
-- 3. Legg til Claude som member_of
|
||||||
|
INSERT INTO edges (id, source_id, target_id, edge_type, metadata, system, created_by)
|
||||||
|
VALUES ('<uuid>', 'd3eebc99-9c0b-4ef8-bb6d-6bb9bd380a44', '<comm-uuid>', 'member_of', '{}', false, '<bruker-uuid>');
|
||||||
|
|
||||||
|
-- 4. Recompute access
|
||||||
|
SELECT recompute_access('<bruker-uuid>', '<comm-uuid>', 'owner', '<owner-edge-uuid>');
|
||||||
|
SELECT recompute_access('d3eebc99-9c0b-4ef8-bb6d-6bb9bd380a44', '<comm-uuid>', 'member', '<member-edge-uuid>');
|
||||||
|
```
|
||||||
|
|
||||||
|
Etter dette vil alle meldinger i chatten automatisk trigge Claude-svar.
|
||||||
|
|
||||||
|
## Drift
|
||||||
|
|
||||||
|
Maskinrommet kjører som systemd-tjeneste direkte på hosten:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status maskinrommet # status
|
||||||
|
sudo systemctl restart maskinrommet # restart etter ny build
|
||||||
|
sudo journalctl -u maskinrommet -f # live-logger
|
||||||
|
```
|
||||||
|
|
||||||
|
Bygg og deploy:
|
||||||
|
```bash
|
||||||
|
cd ~/synops/maskinrommet && cargo build --release
|
||||||
|
sudo systemctl restart maskinrommet
|
||||||
|
```
|
||||||
|
|
||||||
|
## Faser
|
||||||
|
|
||||||
|
- **Fase A (MVP):** Chat-agent — implementert og verifisert
|
||||||
|
- **Fase B:** Autorisasjon og oppgaver (direct vs propose flyt)
|
||||||
|
- **Fase C:** Autonom implementering (claude Code som subprocess for kode-endringer)
|
||||||
|
- **Fase D:** @mentions, typing-indikator, admin-panel
|
||||||
Loading…
Add table
Reference in a new issue