Flerbruker — identitet, medlemskap og tilstedeværelse
Control Center fungerer for én operatør, men modellen under det er fleraktør fra første stund. Mennesker og agenter sender meldinger i de samme områdene, redigerer de samme sakene og vises i den samme oversikten. Å gjøre dette trygt og forståelig koker ned til tre beslutninger: hvem som regnes som en aktør, hva som gir tilgang og hvilken tilstand som deles varig, kontra bare kringkastes i sanntid.
Principaler: brukere og agenter er likeverdige aktører
Seksjon med tittelen «Principaler: brukere og agenter er likeverdige aktører»Alt som registrerer «hvem gjorde dette» — meldinger, saker, gjennomganger,
planer, kjøringslogger, revisjonsoppføringer — løses gjennom en Principal,
en lukket union av UserPrincipal og AgentPrincipal med en kompakt
wire-form (user:<id> / agent:<id>). Attribusjon kollapser aldri N
mennesker (eller N agenter) til én sentinelkonto, så en gjennomgang skrevet av
en agent og en gjennomgang skrevet av et menneske kan skilles fra hverandre
overalt der de dukker opp.
Fordi principalen er identitetsenheten, er den også enheten for inneslutning:
- Rategrenser er per principal, ikke per økt. Flombeskyttelsen på eksterne verktøykall budsjetterer per bruker, ikke per tilkobling: alle enhetene til et medlem trekker fra ett delt, glidende vindu (120 kall i minuttet, hvorav maks 30 kan mutere), så å åpne tre enheter tredobler ikke noens kvote, og ett støyende medlem kan ikke sulte ut de andre.
- Angre er per principal. Hver klients handlingsjournal registrerer bare mutasjonene dens principal utførte. Du kan ⌘Z din egen sakeredigering; du kan ikke angre en kollegas — når du ser den, har den varige banen allerede avgjort den (se nedenfor).
Medlemskap er tilgangsgrensen — ikke paringsnøkkelen
Seksjon med tittelen «Medlemskap er tilgangsgrensen — ikke paringsnøkkelen»To separate legitimasjoner svarer på to separate spørsmål. Paringsnøkkelen (se Fjernstyring og mobil) autentiserer en enhet mot serveren. Medlemskap gir den enhetens bruker rett til å handle inne i et arbeidsområde. En paret enhet hvis bruker ikke har medlemskap i et arbeidsområde, kan verken lese eller mutere det.
Medlemskap er én rad per (arbeidsområde, bruker), lagret i arbeidsområdets egen databasefil — så «hvem er med i dette arbeidsområdet?» er en helt vanlig avgrenset lesing, mens det inverse spørsmålet, «hvilke arbeidsområder er jeg med i?», nødvendigvis spenner over filer og er en av de få godkjente fan-outene på tvers av arbeidsområder. Det er dette arbeidsområdevelgeren kjører før noe arbeidsområde er valgt.
Hver rad har en rolle fra en rangordnet stige med fem nivåer:
| Rolle | Kan |
|---|---|
owner |
Full kontroll, inkludert sletting av arbeidsområdet; nøyaktig én per arbeidsområde |
admin |
Administrere medlemmer, invitasjoner, innstillinger og destruktive operasjoner |
member |
Daglig lesing og skriving: meldinger, saker, agentkjøringer |
viewer |
Skrivebeskyttet i hele arbeidsområdet; glob-mønstre for hemmelighetsutelatelse skjuler matchende stier på flater med kode |
guest |
Samme lesegulv som leser-rollen, på det laveste trinnet i stigen |
Hvert tilgangsvedtak reduseres til «har den som spør, minst rolle X». Gulvet
utledes fra operasjonens type med mindre den erklærer ett eksplisitt: en lesing
trenger guest, en mutasjon trenger member, en destruktiv operasjon trenger
admin. ACL-er per objekt utover repo-tilgangene nedenfor er bevisst utenfor
omfanget.
Invitasjoner er måten medlemskap gis på, fra Innstillinger → Arbeidsområde
→ Medlemmer. En admin lager en engangskode (som en lenke eller QR-kode) som
utløper etter sju dager som standard; serveren lagrer bare kodens SHA-256-hash,
og selve koden vises nøyaktig én gang. Å løse den inn provisjonerer brukeren
JIT, registrerer medlemskapet med invitasjonens rolle (aldri owner —
eierskap overføres eksplisitt, gis aldri via invitasjon) og overlater til
enhetsparing. Enhetslegitimasjoner som lages etter paring, er selv
tidsbegrenset til 30 dager, så en paring er ikke en permanent nøkkel.
Repotilganger ligger under medlemskap. Fordi serveren har fullstendige
utsjekker, må medlemskap i arbeidsområdet alene aldri gi mer rettigheter enn
kodeverten: hver flate som inneholder kode — filer, differ, PR-gjennomgang,
kodesøk — sjekker medlemmets tilgang til det repoet. Tilganger er per
(arbeidsområde, bruker, repo) og rangert none → read → review → write,
der write betyr å drive agentkjøringer som skriver til repoet. En manglende
rad betyr none; eiere og admins har implisitt write på alle tilknyttede
repoer og har ingen rader i det hele tatt.
To baner for samarbeidstilstand
Seksjon med tittelen «To baner for samarbeidstilstand»Control Center deler delt tilstand i to baner med motsatte varighetsregler, fordi de to typene tilstand feiler på motsatte måter.
Den flyktige tilstedeværelsesbanen
Seksjon med tittelen «Den flyktige tilstedeværelsesbanen»Tilstedeværelse — hvem som er pålogget, hvor de er, hva de skriver, hva en
agent gjør akkurat nå — er verdiløs i det øyeblikket den er utdatert. Hvis den
ble lagret, måtte hver gjentilkobling avstemme «databasen sier at Sam redigerer
denne saken» mot virkeligheten. Derfor skrives tilstedeværelse aldri til
databasen. Den lever i en tilstedeværelseshub i minnet på serveren:
klienter publiserer med presence.update, andre klienter abonnerer med
presence.watch, og oppføringer utløper automatisk etter tre tapte hjerteslag
(hjerteslag går hvert 10. sekund; hubben rydder hvert 5.). Det finnes ingenting
å avstemme — bare å la falle.
To egenskaper holder banen til å stole på:
- Identiteten kommer fra økten, aldri fra klientargumenter. Serveren kobler
tilkoblingens autentiserte enhet til en bruker-id; en klient kan bare
oppdatere sin egen tilstedeværelse, så ingen kan forfalske en annen
deltakers status eller posisjon. En eksplisitt
offline-oppdatering (frakobling eller den usynlige bryteren) fjerner oppføringen umiddelbart. - Oversikten formidles gjennom serveren. Klienter utveksler aldri tilstedeværelse direkte, så alle deltakere ser den samme oversikten uansett topologi. Agenter har ingen klient, så serveren syntetiserer oppføringene deres fra levende kjøringstilstand — tenker, kjører, blokkert på en godkjenningsport, ferdig — med én representativ kjøring som avgjør agentens tilstand og posisjon, slik at samtidige kjøringer ikke får oversikten til å flakke.
Utsendingen er lagdelt per konsument: skrivebord og nett ligger på en full lagdeling (maks én oversiktsutsending per 100 ms), telefonen på en oppsummeringslagdeling (per 500 ms), så oppdateringer i markørtakt ikke smelter PWA-en.
En deltakers posisjon — hvor de befinner seg akkurat nå, helt ned til
artefakten — er en lukket union: Space, File (repo + sti + valgfri linje),
Pr, Ticket, PlanNode. Ikke alle posisjoner har et sted å hoppe til: det
finnes ingen rute for filvisning, så en File-posisjon vises som en etikett i
stedet for et reisemål. Banen bærer også myke krav («Sam redigerer denne
saken», «en agent holder denne worktreen»): konflikt synlighet, ikke låser.
Ukjente posisjonstyper parses til null, så en gammel klient bare lar være å
vise det den ikke forstår.
Den varige delte banen
Seksjon med tittelen «Den varige delte banen»Registre som må overleve — saker, det delte Notater-dokumentet i området, meldinger — tar den motsatte veien: autoritative, ordnede og lagrede. Samtidige redigeringer avgjøres av siste skriver vinner, i den rekkefølgen serveren mottok dem, aldri av klientklokker. Avgjørelsen er bevisst finkornet: sakeredigeringer er per kolonne, så to personer som redigerer ulike felt i samme sak, lander begge, og ingen overskriver den andre (arbeidsflytoverganger beholder optimistisk låsing i stedet); Notater-dokumentet i området er én kolonne, så hele dokumentet er LWW, med myke krav på tilstedeværelsesbanen som gjør samtidig redigering synlig i stedet for låst. Det er bevisst ikke en CRDT — bevisbyrden ligger på CRDT-en, og mottaksrekkefølge-LWW pluss synlige krav dekker de faktiske samarbeidsmønstrene.
«Siste skriver» betyr rekkefølgen serveren mottok dem i, aldri en klientklokke — en bærbar maskin med feil klokke kan ikke vinne en redigering den tapte. Bak den varige banen ligger synkroniseringsstrømmen: SQLite-triggere legger hver mutasjon til en endringslogg per arbeidsområde inne i skrivetransaksjonen, og tildeler et monotont sekvensnummer per arbeidsområde i samme transaksjon som mutasjonen selv. En tjeneste på serveren følger den loggen og lager versjonerte delta-rammer i sekvensrekkefølge. Klienter utvikler seg fra fulle øyeblikksbilder til deltaer; et hull i sekvensen setter det lageret tilbake til øyeblikksbildemodus i stedet for å bruke rammer feil.
Følg, styr, ta over, gi tilbake
Seksjon med tittelen «Følg, styr, ta over, gi tilbake»Tilstedeværelsesbanen er ikke bare en oversikt — den driver samarbeidsverbene:
- Følg-modus. Klikk på en deltaker, og klienten din rir på posisjonen deres og navigerer mens de navigerer. Følg varer «til du handler»: i det øyeblikket du navigerer på egen hånd, kobles følgen fra. Et banner som kan avvises, varsler når en annen deltaker setter søkelys på (presenterer) et område du er i.
- Styr. En melding til en kjørende agent kølegges som styring; agenten leser den på nytt før den fortsetter på neste tur, så du kan dytte en kjøring i riktig retning underveis uten å drepe den.
- Ta over. Å overta kontrollen over en samtale setter hver aktive kjøring på pause ved neste rene tur-grense (en Claude Code-kjøring, som ikke har noen trygg grense, stoppes) bak et git-øyeblikksbilde per tur, så overtakelsen kan reverseres. En varig markør blokkerer nye utsendinger inn i området og overlever en serveromstart — serveren gjenopptar aldri automatisk inn i et menneskes halvferdige redigering. Én levende redaktør per worktree er et mykt krav: en andre overtakelse er synlig og avvises i stedet for å slås sammen i det stille.
- Gi tilbake. Å gi tilbake kontrollen legger ut et strukturert diff-sammendrag av worktreen i området, kølegger det som styring for de pausede kjøringene, gjenopptar dem og fjerner markøren.
Autonomibryteren
Seksjon med tittelen «Autonomibryteren»Styring og overtakelse er inngrep i etterkant. Autonomibryteren er den varige innstillingen: per område, per agent, satt fra områdehodet, og den avgjør hva som skjer når en agent når en handling bak en port.
| Nivå | Wire-verdi | Effekt på et verktøykall bak en port |
|---|---|---|
| Bare foreslå | proposeOnly |
Nektes umiddelbart, med en begrunnelse agenten bes formidle videre — den kan beskrive handlingen, men ikke utføre den |
| Handle med godkjenning | actWithApproval |
Godkjenningsporten som feiler lukket: én bekreftelse vises til en tilkoblet operatør, og ingen godkjenner betyr nektet |
| Handle fritt | actFreely |
Forhåndsgodkjent, unntatt der en hard deny-regel i tillatelsesreglene gjelder — en nekt-regel vinner alltid |
| (ikke satt) | null |
Samme som handle med godkjenning: serverens standard |
To ting ligger utenfor bryteren i begge retninger. En modus’ eget utdataverb er
låst og kan aldri nektes, uansett hva bryteren sier — orkestreringsmodus var en
gang strukturelt ute av stand til å sende fra seg det eneste den leverer,
fordi et forhåndsvalg nektet den effektklassen verbet erklærer. Og en hard
deny fra handlingstillatelsesreglene kan ikke overstyres av actFreely.
Solo – ingen regresjon
Seksjon med tittelen «Solo – ingen regresjon»Alt dette er additivt. Arbeidsflyten til en som jobber alene, er uendret: med ett menneske og ingen agenter har tilstedeværelseshubben ingenting å kringkaste, så banen sender sitt første øyeblikksbilde og ligger deretter i ro med null trafikk; LWW- og synkroniseringsmaskineriet er den samme enkelt-skriver-banen som det alltid har vært; og paringsnøkkelen er fortsatt enhetslegitimasjonen den alltid har vært. Medlemskap er allerede tilgangsgrensen — med ett menneske finnes det én eierrad og ingen ekstra grensesnittelementer for oversikten.
- Arbeidsområder og isolasjon: grensen medlemskapet håndhever
- Fjernstyring og mobil: paringsnøkkelen og enhetslegitimasjonen på identitetssiden
- Agentmodellen: agenthalvdelen av principal-unionen
- Livssyklus for agentutsending: kjøringene som styring og overtakelse setter på pause og gjenopptar
- Tillatelsesregler: effektklassepolicyen autonomibryteren spiller sammen med
- Domenehendelser: bussen som sanntidsoppdateringene rir på