Difficulty: Intermediate · You'll need: Go, TypeScript · Size: ~150 lines across 4 layers
What's going on
The system can display a paused container but cannot pause one.
| Evidence |
Location |
paused is a first-class state in the protocol |
packages/protocol/src/container.ts → ContainerState.paused |
| The agent maps it from Docker on every inspect |
apps/agent/internal/docker/service.go → mapContainerInspect |
| The container table offers a "paused" status filter |
apps/web/src/components/ContainerTable.tsx → StatusFilter |
| A way to reach that state |
❌ nowhere |
So an operator can filter for paused containers, and the only way one can appear in that list is if somebody ran docker pause over SSH — the exact thing DockSight exists to avoid.
Why it matters for v0.1.0
start, stop, restart and remove are implemented end to end. pause/unpause are the remaining Docker lifecycle verbs, and they are cheap: unlike exec (roadmap, needs a bidirectional stream) or container creation (roadmap, needs a form and image handling), pause is exactly the same request/reply shape as restart.
Pause is also genuinely useful — freezing a misbehaving container to inspect it without losing its memory state is a normal operational move, and stop destroys that.
The work
Follow container.remove end to end — it is the most recent example and touches every identical spot.
Protocol (packages/protocol/src/container.ts)
CONTAINER_PAUSE: 'container.pause', CONTAINER_UNPAUSE: 'container.unpause' + flat aliases
'pause' | 'unpause' added to ContainerAction
- Two
MessageEnvelope bindings reusing ContainerCommandPayload — neither needs a flag, so no new payload type
- Both added to the
ContainerMessage union and re-exported from index.ts
Agent (apps/agent/internal/)
PauseContainer / UnpauseContainer in docker/service.go, calling sdk.ContainerPause / ContainerUnpause
- Two constants, two dispatcher cases, two inner-switch cases, two
actionFromType entries in communication/client.go
Server
- Two entries in
COMMAND_TYPE; TypeScript will refuse to compile the Record<ContainerAction, string> until you add them
- Two routes in
containers.controller.ts, mirroring restart — @Roles('ADMIN'), ContainerActionBodyDto
Web
ContainerAction widened in types/api.ts, PAST_TENSE and VERB entries in useContainerCommands.ts
- Menu items shown conditionally: Pause only when
state === 'running', Unpause only when state === 'paused'
Things to watch
- No confirmation needed. Pause is fully reversible, so it must not go through
useConfirm — that dialog is reserved for irreversible actions, and using it everywhere trains people to click through it.
- Docker refuses to pause a stopped container and to unpause a running one. Do not pre-check; let Docker's message propagate, the same way remove does.
- Timeout: pause is near-instant; 30s (matching
StartContainer) is ample.
- Fixtures: both messages reuse
ContainerCommandPayload, which has no fixture yet. Adding one for container.pause would cover the shared shape for start/stop/restart too.
Done when
Difficulty: Intermediate · You'll need: Go, TypeScript · Size: ~150 lines across 4 layers
What's going on
The system can display a paused container but cannot pause one.
pausedis a first-class state in the protocolpackages/protocol/src/container.ts→ContainerState.pausedapps/agent/internal/docker/service.go→mapContainerInspectapps/web/src/components/ContainerTable.tsx→StatusFilterSo an operator can filter for paused containers, and the only way one can appear in that list is if somebody ran
docker pauseover SSH — the exact thing DockSight exists to avoid.Why it matters for v0.1.0
start,stop,restartandremoveare implemented end to end.pause/unpauseare the remaining Docker lifecycle verbs, and they are cheap: unlikeexec(roadmap, needs a bidirectional stream) or container creation (roadmap, needs a form and image handling), pause is exactly the same request/reply shape as restart.Pause is also genuinely useful — freezing a misbehaving container to inspect it without losing its memory state is a normal operational move, and
stopdestroys that.The work
Follow
container.removeend to end — it is the most recent example and touches every identical spot.Protocol (
packages/protocol/src/container.ts)CONTAINER_PAUSE: 'container.pause',CONTAINER_UNPAUSE: 'container.unpause'+ flat aliases'pause' | 'unpause'added toContainerActionMessageEnvelopebindings reusingContainerCommandPayload— neither needs a flag, so no new payload typeContainerMessageunion and re-exported fromindex.tsAgent (
apps/agent/internal/)PauseContainer/UnpauseContainerindocker/service.go, callingsdk.ContainerPause/ContainerUnpauseactionFromTypeentries incommunication/client.goServer
COMMAND_TYPE;TypeScriptwill refuse to compile theRecord<ContainerAction, string>until you add themcontainers.controller.ts, mirroringrestart—@Roles('ADMIN'),ContainerActionBodyDtoWeb
ContainerActionwidened intypes/api.ts,PAST_TENSEandVERBentries inuseContainerCommands.tsstate === 'running', Unpause only whenstate === 'paused'Things to watch
useConfirm— that dialog is reserved for irreversible actions, and using it everywhere trains people to click through it.StartContainer) is ample.ContainerCommandPayload, which has no fixture yet. Adding one forcontainer.pausewould cover the shared shape for start/stop/restart too.Done when
docs/roadmap.mdupdated