Know what your agents leave behind.
Trace it to a run. Keep what matters. Review the cleanup.
Quick start · Docs · Integrations · Roadmap · Contribute · Issues
Illustrative walkthrough, not live process output. View the still image.
Closingtime is an open-source CLI and Rust library that records process ownership for coding-agent runs, explains what survives, and lets you review cleanup before stopping anything. It runs offline, with no account or telemetry.
The current prototype covers processes and their TCP listening ports. Worktrees and temporary files/directories are on the roadmap.
Prototype status. The core has been tested locally on macOS and in Linux containers. Real agent workload testing, hosted CI and public binary releases remain pending. See the validation record for evidence and limitations.
A running process or listening port tells you something is still here. Closingtime helps explain which recorded run owns it, where that run started, and why the process is—or is not—eligible for cleanup.
- Separate runs, even in one project. Each wrapper invocation gets its own ID. Native agent session IDs remain separate optional metadata.
- Keep the evidence. Launch registration, inherited session tags and observed ancestry are labelled separately. Recorded ownership survives reparenting.
- Preserve intentional work. Keep a recorded process and its known descendant tree.
- Review what would stop. Cleanup starts with a preview; uncertain targets stay report-only.
- Reuse the core. Embed the Rust library or read the versioned JSON contract without accessing SQLite directly.
Polling does not capture every spawn. Closingtime reports missing or conflicting evidence rather than claiming complete ownership coverage.
From a local source checkout, with Rust and a native C toolchain available:
git clone https://github.com/ekinburak/closingtime.git
cd closingtime
cargo install --path crates/closingtime-cli --locked
closingtime doctorThis prototype builds from a source checkout. Package registry releases and prebuilt binary downloads remain pending. To build without installing:
cargo build --release --locked
./target/release/closingtime --helpPrebuilt binaries and Homebrew are the next distribution priority. Maintainers can prepare a native archive and checksum with the binary packaging guide; these local artifacts are not public releases.
Wrap the command you normally run:
closingtime run --label checkout -- claude
# Or:
closingtime run -- codexThe child inherits normal terminal input/output and its exit status is preserved. Closingtime prints a run ID. When the command exits, inspect what remains:
closingtime sessions
closingtime who --port 3000
closingtime scan --last--last selects the most recent run; --session accepts a full run ID or any unique prefix of one. An unknown process stays unknown; a shared directory alone never establishes ownership.
If a recorded server is intentional, preserve its current identity:
closingtime keep --pid 12345Then review the run:
closingtime clean --last # Preview only
closingtime clean --last --apply # Fresh checks + type yes in a terminalThe example PID is illustrative. Select the actual PID from your ownership lookup. Nothing is automatically cleaned up when a run ends.
| Command | What it does |
|---|---|
run -- <command> |
Start a recorded run, tag the child and observe descendants. |
sessions |
List runs, lifecycle state and surviving resources. |
scan [--session ID | --last] |
Show recorded resources, ownership evidence and cleanup eligibility. |
who --port PORT / who --pid PID |
Explain a current listener or process; report unknown ownership honestly. |
clean --session ID / clean --last |
Preview eligible actions without changing ownership or decisions. |
clean ... --apply |
Refresh the preview, require interactive confirmation and recheck every target. |
recover --session ID / recover --last |
End a run whose wrapper crashed or stopped recording, once its supervisor and root have exited. |
prune [--event-days N] |
Forget runs and processes from earlier boots, and ledger events older than N days (default 30). |
keep --pid PID / unkeep --pid PID |
Preserve or release a recorded identity; ancestor keeps still apply. |
doctor |
Report process-identity, metadata, TCP and signal capabilities. |
export --json |
Export the versioned local ledger, including action history. |
Read commands support --json. export always emits JSON. --state-dir PATH chooses a dedicated private ledger directory. Read commands with no ledger do not create one.
Attribution alone never authorizes a stop. Every eligible target requires:
- Recorded ownership and a confirmed ended run.
- A matching current host, boot, UID, PID, kernel start time and executable.
- Readable, non-conflicting ownership evidence and known unmanaged status.
- No keep decision or protection rule.
- Human review in the CLI, followed by another eligibility and identity check before each signal.
Kept descendants, active or unconfirmed runs, other users' processes, invoking ancestors, system processes and manager-owned services are excluded. Zombies are reported as awaiting parent reaping. Missing end events stay unconfirmed until recover verifies that the wrapper and the run's root have exited.
Cleanup signals individual verified processes: SIGTERM to each reviewed target, one shared three-second grace period, then another check before SIGKILL. Linux requires pidfds and has no plain-PID fallback. macOS has a remaining identity-check/signal race; it is reduced by immediate rechecking, not eliminated.
Piped or JSON-mode apply is refused. The CLI has no --yes, automatic reaper, process-group kill or cgroup kill. Action intent is persisted before signaling, and outcomes remain in the local history.
The 240-case synthetic corpus produced zero incorrectly eligible targets on the tested platforms. That is evidence for those scenarios, not a universal safety guarantee. Coverage and native results →
closingtime-core exposes the same operations used by the CLI:
begin_session → spawn_owned / register_owned → observe → end_session
→ plan_cleanup → apply_plan
An embedding harness must provide its own review and approval before applying a plan. ReviewedApproval acknowledges that caller decision; it is not an authorization token.
| Integration | Start here |
|---|---|
| Rust harness | Minimal recording example |
| Python or another tool | JSON export reader |
| Stable interface | closingtime.session.v1 contract |
The library and CLI are available from this workspace; neither is claimed to be published to crates.io. Portlist/Herdr integrations, hooks and MCP remain future work.
Sessions, observations, keeps and action results live in a private SQLite ledger. Closingtime makes no network calls and does not store full command arguments, prompts, transcripts or arbitrary environment variables.
| Platform | Default state directory |
|---|---|
| Linux | $XDG_STATE_HOME/closingtime, or ~/.local/state/closingtime |
| macOS | ~/Library/Application Support/closingtime |
Stored metadata includes project/executable paths and process identities. Tags and local registration express cooperative provenance; they are not an adversarial security boundary. See the usage and safety guide for permissions, terminal signals, keep inheritance and recording limits.
cargo fmt --all --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test --workspace --locked
python3 tests/terminal_smoke.py --binary target/debug/closingtimeThe suite covers model safety decisions, concurrent ledger writes, actual detached TCP listeners, SIGTERM escalation, terminal behavior and lookup latency with 200 live recorded processes. The GitHub Actions checks run on Linux and macOS; see the validation record for the evidence behind published results.
See the contribution guide for setup, verification and scope. The README artwork source includes the wordmarks, motion assets and regeneration command.
| Looking for | Start here |
|---|---|
| Everyday use and cleanup behavior | Usage and safety guide |
| Embedding in a Rust harness | Recording example |
| Reading data from another language | Python example · JSON contract |
| Test evidence and remaining limitations | Validation record |
| Supported scope and upcoming work | Requirements · Roadmap |
| Bugs, questions and feature proposals | GitHub Issues |
| Contributing a change | Contribution guide |
Ownership explanations, keep controls, cleanup safety and local history belong in the complete free core. A possible future team service is a hypothesis, not a current offering. There is no paid tier or pricing commitment.
The original discovery research is outside this source distribution; its market estimates are not product claims.