Drift og klienter
Control Center er ikke ett program. Det er en tynnklientarkitektur: en headless server som eier dataene dine, og et sett klienter som tegner et grensesnitt over én enkelt RPC-tilkobling til den. Å forstå denne delingen forklarer hvorfor noe kjører der det gjør, og hva hver klient kan og ikke kan nå.
Serveren eier dataene
Seksjon med tittelen «Serveren eier dataene»En prosess som heter cc_server holder databasene — en liten global.db
for tilstand på tvers av hele serveren, pluss én SQLite-fil per
arbeidsområde, åpnet lat — og
kjører det langvarige arbeidet: pipeline-motorer, avstemmere, MCP-verktøyflaten
og orkestreringlytteren. Alt som må overleve et vindu, eller som to klienter
skal se identisk, bor der.
Ingen klient åpner en databasefil selv. I stedet holder hver klient én
RemoteRpcClient og utfører repo-operasjoner og abonnementer over den.
Serveren autentiserer tilkoblingen mot en forhåndsdelt nøkkel for parede
enheter — og slutter deretter å bry seg om tilkoblingen. En økt er ikke
bundet til et arbeidsområde. Dispatcheren er tilstandsløs: hvert
arbeidsområde-avgrensede kall bærer sin egen workspace_id i argumentene, og
et kall som utelater det, avvises.
Det er med vilje, og det er det som lar to klienter på én server sitte i ulike arbeidsområder uten et serverlagret «gjeldende arbeidsområde» de kan være uenige om. Isolasjon håndheves i stedet per kall, i fire trinn:
- Operasjonen erklærer om den er arbeidsområde-avgrenset; er den det og ingen
workspace_idkom med, avvises kallet. - Id-en som angis, må være et registrert arbeidsområde, sjekket før noe
åpner en database — ellers ville en ukjent id skape en tom
spøkelses-
workspace.dbved hver forespørsel. En id som ikke finnes, er et «ikke funnet». - Kallers
WorkspaceRolemå oppfylle operasjonens minstekrav, utledet fra typen: lesing krever gjest, endring krever medlem, destruktive operasjoner krever admin. - En operasjon som eksponerer repo-innhold, krever i tillegg en tilgang per
repo på nivået den erklærer —
none/read/review/write— slik at arbeidsområdemedlemskap aldri stilltiende gir flere rettigheter enn kodeverten.
Setningen som betyr noe: å ha en paringsnøkkel er ikke tilgangsgrensen; medlemskap er det.
Hvorfor dele det slik
Seksjon med tittelen «Hvorfor dele det slik»Tre press førte mot en server:
- Én kilde til sannhet. En skrivebordsapp og en telefon, eller en bærbar og en stasjonær, bør se samme flåtetilstand. Hvis hver av dem eide sin egen database, ville de gli fra hverandre. Én server gjør at hver klient leser de samme levende dataene.
- Nettet kan ikke betjene seg selv. En nettleser kan ikke starte en delprosess eller åpne en lokal fil, så et nettbygg kan aldri eie databasen eller kjøre en agent. Det må snakke med en server som gjør det. I stedet for å bygge en andre datasti kun for nettet, ble skrivebordsappen ført inn på den samme stien.
- Headless drift. En server du kan kjøre på en liten boks — tilgjengelig fra en telefon på toget eller en nettleser hvor som helst — er nyttigere enn et GUI du må la stå åpent.
Avveiningen er at serveren nå er en avhengighet: kjører den ikke, fungerer ingenting. Skrivebordsappens standardsvar på det er å starte en selv.
Klientene
Seksjon med tittelen «Klientene»Fem klienter når serveren, hver med en annen form og tillitsprofil.
Skrivebordsappen
Seksjon med tittelen «Skrivebordsappen»Flutter-skrivebordsapplikasjonen (macOS, Windows, Linux) er fullklienten. Ved første oppstart spør den hvordan den skal kjøre, og husker deretter valget:
- Lokal: start og overvåk en
cc_serverpå denne maskinen — standardoppsettet, selvstendig og for én bruker. Skrivebordsappen starter serveren, som eier databasen under app-support-roten og snakker med den over loopback. - Ekstern: koble til en
cc_serversom kjører et annet sted, over en sikker WebSocket. Dataene ligger på den serveren; denne skrivebordsappen er bare en gjengiver.
I begge tilfeller erstatter den resulterende RPC-klienten appens dataleverandør, slik at hele brukergrensesnittet — hver skjerm, hver funksjon — leser og skriver gjennom serveren. Skrivebordsappen tar aldri på databasefilen direkte.
Nettklienten
Seksjon med tittelen «Nettklienten»Nettbygget er den samme Flutter-appen kompilert for å kjøre i en nettleser,
hostet på app.usectrl.dev, så det er ingenting å
installere. En nettleser kan ikke starte en delprosess, så nettklienten er
alltid ekstern: den ringer opp en cc_server over wss:// og tegner hele
skrivebordsgrensesnittet. Når den er tilkoblet, viser den de samme skjermene
mot den samme flåten, fordi det er den samme koden over den samme RPC-en.
Hullene er de få stedene som trenger en innebygd egenskap nettleseren ikke har —
kvalitetslaget for møteopptak nedenfor er det viktigste, og varsler fra
operativsystemet er et annet.
Dette er hvorfor «ingen nedlasting» og «ingen server» er to forskjellige
påstander. Nettklienten fjerner installasjonen; den fjerner ikke serveren. Det
den ringer opp, kan være en cc_server på den samme bærbare maskinen —
ws://localhost:9030, som ikke trenger sertifikat fordi nettlesere regner
loopback som pålitelig — eller en på en annen maskin, som må være tilgjengelig
over wss:// med et sertifikat nettleseren stoler på. cc_server nekter å
binde en adresse utenfor loopback uten TLS, så en ekstern server betyr enten
serverens eget sertifikat, en TLS-avsluttende proxy, eller en tunnel eller VPN
som skaffer ett.
Selve nettpakken hostes separat fra serveren den snakker med. En frittstående
cc_server betjener RPC-endepunktet, MCP-flaten og proksyene sine, men
ikke en nettpakke — den statiske filstien finnes i serveren, men ingen
webrot er konfigurert på den frittstående binærfilen, så den har ingenting å
betjene på /. Den publiserte containeravbildningen cc-webapp er det som
hoster nettpakken, og scripts/build_web.sh er det som bygger den. En server
godtar bare nettleser-origins som står på --allowed-origins-listen, som
standard er https://app.usectrl.dev, så egen hosting av nettpakken betyr å
legge til dens origin.
Medier (avatarer, bilder i strømmen, PR-skjermbilder) går gjennom serverens proxy-endepunkt i stedet for å treffe oppstrømsverter direkte, slik at en nettleser aldri henter en vilkårlig origin. Den utrullede klienten setter en per-forespørsel Content-Security Policy ut fra en ikke-sensitiv informasjonskapsel, slik at bare origin til den tilkoblede serveren tillates.
Telefonfølgesvenn (cc_remote)
Seksjon med tittelen «Telefonfølgesvenn (cc_remote)»Remote-appen er en egen, lettere klient — en Flutter-nett-PWA på remote.usectrl.dev. Den er med vilje ikke hele appen. Den pares over et meglet WebSocket-relé med ende-til-ende-forsegling og snakker en overveiende lesende del av verktøyflaten: les saker, meldinger og nyhetsstrømmen; send et svar eller oppdater en sak.
En telefon er en aktor med lavere privilegier enn en lokal agent. En verktøypolicy med standardavvisning, en forhåndsdelt nøkkel som forsegler hver ramme, en øktkapabilitet som stenger privilegerte operasjoner (for eksempel parring) ute fra en følgesvennklient, sjekkene av rolle og repo-tilgang per kall beskrevet ovenfor, og hastighetsbegrensning hindrer at en godkjent (eller lekket) parring blir full fjernstyring. Se Fjernstyring og mobil for hele sikkerhetsmodellen.
MCP-klienter
Seksjon med tittelen «MCP-klienter»Eksterne verktøy — editorer, andre agenter, CLI-er — som snakker Model Context Protocol, kobler til serverens MCP-flate og bruker det typede verktøyregisteret. Dette er den programmerbare integrasjonsveien; det er ikke et GUI. Se Bruk MCP-serveren og MCP-verktøyreferansen.
Flåteutførere (cc_worker)
Seksjon med tittelen «Flåteutførere (cc_worker)»En cc_worker er en headless ren Dart-binærfil som pares med en
cc_server, erklærer vertens kapabiliteter og henter leide jobber for
utførelse. Den strømmer prosesshendelser tilbake over den samme RPC-en og
holder ingen varig tilstand: ingen database, ingen autentisering, ingen
godkjenninger, ingen budsjetter — de forlater aldri cc_server. En worker er
en lem, ikke en ekstra hjerne. Én autoritativ server, N dumme lemmer; det
finnes ingen konsensus, ingen trafikk worker til worker.
Leaset utførelse er fortsatt bare lease-infrastruktur. agentRun er den eneste
typen som kjører en ekte kommando (CC_JOB_COMMAND, eller en ekkoet prompt
hvis ingen ble oppgitt). pipelineStep, codeIndex, goldenRender,
benchmark og evalBatch utfører foreløpig en sondering med git --version /
rev-parse HEAD, slik at strømmestien blir prøvd uten å late som om disse
jobbene kjørte.
Det den annonserer, er operativsystemet, CPU-arkitektur, antall kjerner, RAM, om
et Flutter-SDK er tilgjengelig, og hvilke sandkasse-backender verten har (ingen
på Windows). En dedikert worker annonserer også alltid alwaysOn og
acceptsParallel, og det er disse planleggeren legger til grunn når den
plasserer etter strategien fest → foretrekk → fordel. Det finnes ingen GPU- eller
ML-sondering.
En enslig skrivebordsinstallasjon merker ingenting av dette, fordi vanlig
utsending ikke går gjennom flåten i det hele tatt. Det finnes en implisitt
worker i prosessen, registrert for serververten, men det er en
registreringssøm uten kjørere koblet til — en jobb som faktisk plasseres på den
lokale workeren, mislykkes i stedet for å kjøre. I dag er det bare en ekte
cc_worker som utfører leide jobber.
Hva kjører hvor
Seksjon med tittelen «Hva kjører hvor»| Ansvarsområde | Server (cc_server) |
Flåteutfører (cc_worker) |
Skrivebordsklient | Nett-/telefonklient |
|---|---|---|---|---|
| Databaser (Drift/SQLite) | eier dem | — | — | — |
| Autentisering, godkjenninger, budsjetter, identitet | eier dem | — | — | — |
| Pipelines, avstemmere, orkestreringlytter | kjører det | — | — | — |
| MCP-verktøyflate | betjener den | — | — | — |
| Agentutførelse | kjører det (eller leaser det ut) | utfører leide jobber | — | — |
| UI-gjengivelse | — | — | full | full (nett) / mest lesing (telefon) |
| Møteopptak (mikrofon + møtelyd) | — | — | innebygd opptak | bare nett, via skjermdelingslyd |
| Kalender-OAuth (Google) | lagrer tokener | — | — | — |
De to nivåene bruker ikke samme sandkasse. cc_server pakker kjøringene den
utfører selv, inn i vertens OS-sandkasse der en backend finnes — Seatbelt på
macOS, bubblewrap på Linux og WSL2 — og faller tilbake på de andre grensene på
Windows eller uten bwrap og socat. cc_worker bruker ingen sandkasse i
det hele tatt. Den annonserer en sandbox-kapabilitet, slik at serveren kan
plassere jobber etter plattform, men ingenting i workeren tar den i bruk: en
leaset jobb startes direkte, begrenset av miljøet til leasen og worktreet den
fikk. Å lease ut arbeid flytter derfor utførelsen utenfor sandkassen, selv på
en vert som har en. Se
Sandkasse og sikkerhet for
hva som begrenser en kjøring i hvert tilfelle.
Møteopptak skjer på en klient, fordi det trenger en mikrofon og møtets lyd — en server i et skap kan ikke ta opp samtalen din. Opptaket oppsummeres deretter av serverens pipeline, og notatene lagres der hver klient kan lese dem.
Nettklienten tar også opp, noe tabellens form kan skjule: den fanger mikrofonen pluss et lydspor for skjermdeling i nettleseren og strømmer 16 kHz PCM til serveren. Den krever dette lydsporet, og feiler derfor eksplisitt der nettleseren ikke tilbyr ett. Det som virkelig bare finnes på skrivebordet, er kvalitetslaget rundt opptaket — ekkoutnulling på signalnivå via den innebygde prosessoren, inngangsnivåmåleren og advarselen om død mikrofon, å kjøre en oppsummering på nytt, å avbryte behandling og kalenderens handling for opptak og kobling.
Parring og tillit
Seksjon med tittelen «Parring og tillit»Hver klient beviser hvem den er med en forhåndsdelt nøkkel som legges inn én gang:
- Skrivebordsappen i lokal modus genererer en fersk nøkkel ved hver oppstart og gir den til den startede serveren via miljøet, slik at ingenting hemmelig lagres på skrivebordet.
- Eksterne klienter (ekstern skrivebordsapp, nett, telefon) bruker en nøkkel
utstedt av serverens
pair-kommando og lagret i OS-nøkkelringen (eller lokalt på telefonen).
Tilbakekalling er umiddelbar, ikke utsatt. Serveren overvåker tabellen over parede enheter og avslutter enhver åpen økt der enheten har forlatt det aktive settet, innen sekunder — både på den direkte WebSocket-stien og på relé-stien. Du trenger ikke vente på at enheten kobler til på nytt for å kutte den.
Nøkkelen går aldri gjennom en URL som en statisk vert kan se. Når den kommer
via en lenke — på telefonen eller i en nettleser — ligger den i
URL-fragmentet, delen etter #, som nettleseren aldri sender til serveren
som hoster siden. Det er invarianten som er verdt å huske, og den gjelder for
begge. Nettklienten har to andre innganger: tilkoblingsskjemaet, der du limer
inn en server og en nøkkel direkte, og en invitasjonskode, som den løser inn
mot en legitimasjon utstedt bare for den nettleseren.
Relaterte konsepter
Seksjon med tittelen «Relaterte konsepter»- Arbeidsområder og isolasjon: hvorfor hvert RPC-kall bærer sin egen arbeidsområde-id, og hvordan databasedelingen gjør isolasjonen strukturell
- Arkitektur: hvordan kodebasen er strukturert rundt serveren og klientene
- Fjernstyring og mobil: parring av telefon og sikkerhetsmodellen
Relaterte veiledninger
Seksjon med tittelen «Relaterte veiledninger»- Kjør en headless server: start
cc_serverog par en klient - Koble til en ekstern server: pek skrivebords- eller nettklienten mot en server et annet sted
- Koble til en enhet: legg til en telefon, en ny nettleser eller en annen skrivebordsapp
- Kjør en flåteworker: legg til en
cc_workersom henter leide jobber