Add the ability to "fork" an existing town, creating a new town that inherits the source town's configuration and bead history. This is useful for:
forkTown(sourceTownId, targetOwnerType, targetOwnerId, newTownName):
1. Verify caller has read access to source town
2. Create town record in owner DO (GastownUserDO or GastownOrgDO)
3. sourceTownDO.exportForFork() → serialized JSON payload
4. Build rig ID mapping: oldRigId → newRigId
5. Create new TownDO, call setTownId()
6. newTownDO.importFork(payload, rigIdMapping):
- INSERT beads (remapping rig_id via mapping)
- INSERT bead_events (for copied beads only)
- INSERT bead_dependencies (for copied beads only)
- INSERT review/escalation/convoy_metadata
- INSERT rigs (with new IDs)
7. Set TownConfig: copy settings, set new ownership, mint fresh credentials
8. For each rig: configureRig() + refreshGitCredentials()
9. Register rigs in owner DO
Summary
Add the ability to "fork" an existing town, creating a new town that inherits the source town's configuration and bead history. This is useful for:
What Gets Copied
Settings (from TownConfig KV)
default_model,role_models,small_model)Structural Data (SQL tables)
rigsgit_urlanddefault_branchbeadsassignee_agent_bead_id, resetdispatch_attemptsbead_eventsbead_dependenciesreview_metadataauto_merge_ready_since,last_feedback_check_atescalation_metadataconvoy_metadatalanded_at IS NOT NULL)What Gets Skipped
agent_metadata— runtime state, agents created fresh on demandagent_nudges— ephemeral runtime messagestown_events— reconciler queue, ephemeralWhat Gets Minted Fresh
kilocode_token(per new owner viamintKilocodeToken)refreshGitCredentialsfor new owner)owner_user_id,organization_id,owner_type, etc.)TownContainerDOinstance, keyed by new town ID)Architecture
Export/Import via Worker Layer
Key Design Decisions
parent_bead_idandbead_dependenciesedges intact without remapping.user_rigstable, so new UUIDs prevent collisions. Allrig_idreferences in copied beads are remapped.Cross-Ownership Support
Edge Cases
landed_at IS NOT NULL). Active convoys reference in-progress branches and agents that won't exist in the fork.bead_dependencieshas FK constraints. Only copy edges where bothbead_idanddepends_on_bead_idare in the copied set.bead_events.agent_id,beads.created_by, andmetadata.source_agent_idwill reference agent IDs that don't exist in the fork. This is fine for read-only history display.beads.ts:282) to avoid inconsistency.Implementation Surface
New Code
TownDO.exportForFork()— RPC method, queries all copyable tables, returnsForkExportPayloadTownDO.importFork(payload, rigIdMapping)— RPC method, bulk inserts with remappingforkTown/forkOrgTowntRPC mutations — orchestrate the full flowExisting Code Touched
src/dos/Town.do.tsexportForFork()andimportFork()RPC methodssrc/trpc/router.tsforkTown/forkOrgTownmutationssrc/dos/GastownUser.do.tscreateTown()+createRig()src/dos/GastownOrg.do.tscreateTown()+createRig()src/dos/town/beads.tssrc/dos/town/rigs.ts