Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,16 @@ Tool-agnostic conventions for AI agents working in this repository. (Claude Code
- Concurrency designed-in (parallel `jwalk` scan).

## CLI conformance (SFRS)
- Global flags: `--json` / `--format`, `--dry-run` / `--apply`, `--yes`, `--color`, `--no-color`.
- JSON envelope: `{ metadata, data }` with maintainer + website; UTC `Z` timestamps.
- Commands: `scan`, `list`, `clean`, `schema`, `describe`, `tui`. Run `vacuum schema`
for the authoritative, function-calling-ready contract; `vacuum describe` for a manifest.
- Global flags: `--json` / `--format {human,json,jsonl,explore}`, `--fields`, `--apply`,
`--purge`, `--yes`/`--force`, `--verbose`/`-v`, `--quiet`/`-q`, `--color`, `--no-color`.
- JSON envelope: `{ metadata, data }` with maintainer + website; UTC `Z` timestamps;
compact when piped, pretty on a TTY; optional fields omitted when absent.
- Errors (machine mode): `{ "error": { code, exit_code, message, hint, timestamp,
command, docs_url } }` on stderr; `hint` is a runnable recovery command. stdout stays data-only.
- Canonical exit codes: `0` ok · `1` failure · `2` usage · `3` not-found · `4` refused/permission ·
`5` conflict · `127` missing tool.
- Agent env detection (`AI_AGENT`, `AGENT`, `CI`, `CLAUDECODE`, `CURSOR_AGENT`, `GEMINI_CLI`)
suppresses the TUI and prefers machine output.

Expand Down
170 changes: 170 additions & 0 deletions LICENSES/CC-BY-SA-4.0.txt

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ info: $(TEXI)
makeinfo --no-split $(TEXI) -o doc/vacuum.info

html: $(TEXI)
makeinfo --html --no-split $(TEXI) -o doc/vacuum.html
makeinfo --html --no-split --css-include=doc/spacecraft.css $(TEXI) -o doc/vacuum.html

pdf: $(TEXI)
texi2pdf -q -o doc/vacuum.pdf $(TEXI)
texi2pdf -q --texinfo=@afourpaper -o doc/vacuum.pdf $(TEXI)

doc: info html pdf

Expand Down
11 changes: 11 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ path = "**"
precedence = "override"
SPDX-FileCopyrightText = "2026 Mohamed Hammad <Mohamed.Hammad@SpacecraftSoftware.org>"
SPDX-License-Identifier = "GPL-3.0-or-later"

# The Texinfo manual is document-class, so it is CC-BY-SA-4.0 (Standard §4.1.1),
# not software-class GPL. A later, more specific annotation wins over the `**`
# override above, keeping the manual's REUSE metadata aligned with its
# @copying grant. Scoped to the .texi sources so software-class build assets
# under doc/ (e.g. spacecraft.css) stay GPL-3.0-or-later.
[[annotations]]
path = "doc/*.texi"
precedence = "override"
SPDX-FileCopyrightText = "2026 Mohamed Hammad <Mohamed.Hammad@SpacecraftSoftware.org>"
SPDX-License-Identifier = "CC-BY-SA-4.0"
72 changes: 72 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
name: vacuum
description: >-
Fast, safe disk-space recovery for the terminal. Scans disk usage in
parallel, groups reclaimable space into categories (build artifacts,
package-manager garbage, app caches, large files), and removes selected
items safely — dry-run by default, XDG trash unless --purge.
license: GPL-3.0-or-later
homepage: https://Vacuum.SpacecraftSoftware.org/
maintainer: Mohamed Hammad <Mohamed.Hammad@SpacecraftSoftware.org>
---

<!-- SPDX-FileCopyrightText: 2026 Mohamed Hammad <Mohamed.Hammad@SpacecraftSoftware.org> -->
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->

# Vacuum — capability surface

`vacuum` is a dual-mode (human + agent) CLI plus an interactive TUI. It conforms
to the Spacecraft Software Dual-Mode Self-Documenting CLI Standard (SFRS v1.0.0).

## Discover the surface programmatically

```sh
vacuum schema # JSON Schema (Draft 2020-12) of every command — drops into
# Anthropic input_schema / MCP inputSchema unchanged
vacuum describe --json # compact capability manifest (commands, categories, safety)
```

Prefer `vacuum schema` over parsing `--help`: it is the authoritative, stable
contract.

## Commands

| Command | Purpose | Mutates? |
|---------|---------|----------|
| `vacuum scan [PATHS…] [--limit N]` | Largest consumers per path | read-only |
| `vacuum list [--category C] [--root P]` | Reclaimable candidates by category | read-only |
| `vacuum clean [--category C] [--root P] [--apply] [--purge] [--yes]` | Remove space | **write** (dry-run unless `--apply`) |
| `vacuum schema` | Emit the command-surface JSON Schema | read-only |
| `vacuum describe` | Emit the capability manifest | read-only |
| `vacuum tui` | Launch the interactive TUI | interactive |

Categories: `build-artifacts`, `package-gc`, `caches`, `large-files`.

## Output contract

- `--json` / `--format json` — single `{ metadata, data }` envelope; UTC `Z`
timestamps; compact when piped, pretty on a TTY; absent optional fields omitted.
- `--format jsonl` — one record per line, unenveloped, for streaming.
- `--fields a,b,c` — project records to named keys (token economy).
- Errors in machine mode: `{ "error": { code, exit_code, message, hint, … } }`
on stderr, where `hint` is a runnable recovery command. stdout stays clean.

## Exit codes

`0` ok · `1` general failure · `2` usage error (fix args, don't retry) ·
`3` not found · `4` permission/safety refusal · `5` conflict ·
`127` required external tool missing.

## Agent environment

`AI_AGENT`, `AGENT`, or `CI` (non-empty) ⇒ JSON, no color, no TUI,
non-interactive. `CLAUDECODE` / `CURSOR_AGENT` / `GEMINI_CLI` are informational
only and do not change the format.

## Safety (do not assume otherwise)

Dry-run is the default; `--apply` is required to act and, non-interactively,
also `--yes`/`--force`. Deletions go to the XDG trash unless `--purge`. Vacuum
stays within `$HOME` plus explicit `--root`s, refuses protected system paths,
never follows symlinks on delete, and never escalates privileges (it prints the
`sudo` command for privileged GC instead).
16 changes: 15 additions & 1 deletion crates/vacuum-cli/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,17 @@ use crate::cli::{Format, GlobalArgs};
pub enum OutputMode {
/// Human-readable text.
Human,
/// Machine-readable JSON envelope.
/// Machine-readable JSON envelope (single document).
Json,
/// Newline-delimited JSON: one record per line.
Jsonl,
}

impl OutputMode {
/// Whether this mode emits machine-readable JSON (enveloped or streamed).
pub fn is_machine(self) -> bool {
matches!(self, Self::Json | Self::Jsonl)
}
}

/// Environment variables that signal an AI agent / CI is driving the CLI.
Expand Down Expand Up @@ -41,9 +50,14 @@ pub fn output_mode(global: &GlobalArgs) -> OutputMode {
if global.json || global.format == Some(Format::Json) {
return OutputMode::Json;
}
if global.format == Some(Format::Jsonl) {
return OutputMode::Jsonl;
}
if global.format == Some(Format::Human) {
return OutputMode::Human;
}
// `--format explore` requests the TUI; when that cannot run (agent/pipe) the
// data still has to render, so it degrades to JSON like any other pipe.
if is_agent() || !std::io::stdout().is_terminal() {
return OutputMode::Json;
}
Expand Down
Loading
Loading