CLI Reference
Panopticas has seven commands. Every one of them accepts --json.
| Command | Purpose |
|---|---|
assess |
Identify the file type and tags of every file in a directory |
file |
Everything panopticas knows about one file |
urls |
Every HTTP/HTTPS URL referenced across a directory |
ai |
AI coding agent artifacts, by product and kind |
tags |
Every tag panopticas can assign |
languages |
Every language it recognises |
filetypes |
Every file type, languages or not |
Run panopticas COMMAND --help for the same options inline.
Global behaviour
panopticas --version prints the installed version. panopticas with no
command prints help and exits 0 — not 2, which is what Click does by
default for a group with no subcommand.
Directory-scanning commands (assess, urls, ai) honour .gitignore. Each
has a flag to override that; note the spelling differs between them, --all-files
on ai and -all-files on urls, because the repository has always mixed
single- and double-dash long options.
Exit codes
| Code | Meaning |
|---|---|
0 |
Success, including --help and the bare panopticas invocation |
2 |
Bad arguments — missing, or the wrong kind of path |
Path arguments are type-checked at the CLI boundary, so a mistake fails loudly instead of producing empty output:
$ panopticas assess src/app.py
Usage: panopticas assess [OPTIONS] [DIRECTORY]
Try 'panopticas assess --help' for help.
Error: Invalid value for '[DIRECTORY]': Directory 'src/app.py' is a file.
$ panopticas file src
Error: Invalid value for 'FILE': File 'src' is a directory.
JSON output
Every command accepts --json, also spelled -json.
In JSON mode stdout carries the document and nothing else — the progress
banner is redirected to stderr — so output pipes cleanly into jq or any
parser without a stripping step:
$ panopticas assess --json 2>/dev/null | jq '.files[] | select(.language == "Python") | .path'
"src/app.py"
$ panopticas assess --json 2>&1 >/dev/null
Assessing current directory.
Every document is a JSON object, never a bare array, so fields can be added without breaking consumers.
assess
Identify the file type and metadata tags of every file in a directory.
panopticas assess [OPTIONS] [DIRECTORY]
DIRECTORY defaults to the current directory. It must be a directory.
| Option | Effect |
|---|---|
-unknown |
Show only files whose type could not be identified |
--lines |
Add a line count column, and a total |
--json, -json |
Emit JSON |
$ panopticas assess
Assessment of .
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ File ┃ Language ┃ Meta ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ requirements.txt │ Text │ pip, Python, PyPi, │
│ │ │ dependencies │
│ pyproject.toml │ TOML │ build, dependencies, Python │
│ .gitignore │ Gitignore │ Git, ignore │
│ CLAUDE.md │ Markdown │ AI, Claude, instructions │
│ .claude/commands/build.md │ Markdown │ AI, Claude, command │
│ src/app.py │ Python │ │
└───────────────────────────┴───────────┴────────────────────────────────┘
6 files
Long paths fold onto a second line rather than being truncated — an ellipsis would cut the filename, which is the part identifying the row.
-unknown reports totals for the rows it shows, not for every file scanned.
JSON
| Field | Type | Notes |
|---|---|---|
directory |
string | As given on the command line |
count |
number | Rows in files, after -unknown filtering |
files[].path |
string | Relative to directory |
files[].language |
string | "Unknown" when undetected — never null |
files[].meta |
array of string | Tags; empty array when none |
files[].lines |
number or null | --lines only; null for binary and unreadable files |
total_lines |
number | --lines only; excludes the null entries |
{
"directory": ".",
"count": 6,
"files": [
{
"path": "requirements.txt",
"language": "Text",
"meta": ["pip", "Python", "PyPi", "dependencies"]
},
{
"path": "src/app.py",
"language": "Python",
"meta": []
}
]
}
file
Everything panopticas can determine about a single file.
panopticas file [OPTIONS] FILE
FILE is required and must be a file, not a directory.
| Option | Effect |
|---|---|
--json, -json |
Emit JSON |
$ panopticas file src/app.py
Assessing filetype for file src/app.py
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Method ┃ Result ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ File extension │ .py │
│ File type │ Python │
│ Shebang │ #!/usr/bin/env python3 │
│ Shebang Language │ Python │
│ Meta │ │
│ URLs │ https://example.com/docs │
└──────────────────┴──────────────────────────┘
This is the only command that reads file contents beyond the first line — it extracts URLs from the whole file.
JSON
| Field | Type | Notes |
|---|---|---|
file |
string | As given on the command line |
extension |
string | The basename when the file has no extension |
filetype |
string or null | null when the extension is not recognised |
shebang |
string or null | The raw first line, when it is a shebang |
shebang_language |
string or null | Derived from shebang |
meta |
array of string | Tags; empty array when none |
urls |
array of string | HTTP/HTTPS URLs found in the file |
{
"file": "src/app.py",
"extension": ".py",
"filetype": "Python",
"shebang": "#!/usr/bin/env python3",
"shebang_language": "Python",
"meta": [],
"urls": ["https://example.com/docs"]
}
Note that filetype here is the extension lookup only. It is null for a
file identified by basename or shebang alone, where assess would still report
a language.
urls
Every HTTP/HTTPS URL referenced across a directory.
panopticas urls [OPTIONS] DIRECTORY
DIRECTORY is required for this command — unlike assess and ai, it does
not default to the current directory. It must be a directory.
| Option | Effect |
|---|---|
-all-files |
Include gitignored files (single dash) |
--json, -json |
Emit JSON |
$ panopticas urls .
URLs in .
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Filename ┃ URLs ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ requirements.txt │ │
│ pyproject.toml │ │
│ .gitignore │ │
│ CLAUDE.md │ │
│ .claude/commands/build.md │ │
│ src/app.py │ https://example.com/docs │
└───────────────────────────┴──────────────────────────┘
6 files
Every scanned file gets a row, including those with no URLs. Binary files are reported as having no URLs rather than aborting the scan.
JSON
| Field | Type | Notes |
|---|---|---|
directory |
string | As given on the command line |
count |
number | Files scanned, not URLs found |
files[].path |
string | Relative to directory |
files[].urls |
array of string | Empty array when none |
{
"directory": ".",
"count": 6,
"files": [
{ "path": "pyproject.toml", "urls": [] },
{ "path": "src/app.py", "urls": ["https://example.com/docs"] }
]
}
To get a flat, deduplicated list:
$ panopticas urls . --json | jq -r '.files[].urls[]' | sort -u
ai
Find the artifacts left by AI coding agents, with the product and the kind of artifact each one is.
panopticas ai [OPTIONS] [DIRECTORY]
DIRECTORY defaults to the current directory. It must be a directory.
| Option | Effect |
|---|---|
--all-files |
Include gitignored files, and bare AI directories (double dash) |
--json, -json |
Emit JSON |
$ panopticas ai
Assessing current directory.
AI artifacts in .
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Path ┃ Product ┃ Kind ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ .claude/commands/build.md │ Claude │ command │
│ CLAUDE.md │ Claude │ instructions │
└───────────────────────────┴─────────┴──────────────┘
2 AI paths • Claude (2)
Detection is path-based only — no file is opened to determine AI metadata. See the AI detection rules reference for every rule and the source that confirms it.
--all-files additionally emits the AI directories themselves, with
kind: "directory":
$ panopticas ai --all-files --json 2>/dev/null | jq -r '.paths[] | "\(.kind)\t\(.path)"'
directory .claude/
directory .claude/commands/
command .claude/commands/build.md
instructions CLAUDE.md
JSON
| Field | Type | Notes |
|---|---|---|
directory |
string | As given on the command line |
count |
number | Entries in paths |
products |
object | Product name to count, most-used first, then alphabetical |
paths[].path |
string | Relative to directory, sorted |
paths[].product |
string | Brand-level: Claude, not Claude Code |
paths[].kind |
string | One of the 14 artifact kinds |
{
"directory": ".",
"count": 2,
"products": { "Claude": 2 },
"paths": [
{ "path": ".claude/commands/build.md", "product": "Claude", "kind": "command" },
{ "path": "CLAUDE.md", "product": "Claude", "kind": "instructions" }
]
}
products is the quickest answer to “which AI tools does this repo use?”:
$ panopticas ai --json 2>/dev/null | jq -r '.products | keys[]'
Claude
Vocabularies
Three commands print what panopticas knows, taking no arguments beyond --json.
panopticas tags
panopticas languages
panopticas filetypes
| Command | Answers |
|---|---|
tags |
Every tag that can appear in an assess Meta column |
languages |
Every file type that is a programming language |
filetypes |
Every file type, languages and non-languages alike |
languages is a subset of filetypes; the remainder are things like PNG,
Lock and Gitignore that have a type but are not languages.
The tag vocabulary is derived from the detection rules themselves rather than maintained as a separate list, so it cannot drift from what the tool actually assigns.
$ panopticas tags
.NET agent Agents AI Aider
Amazon Q Apache ASP.NET Augment Azure DevOps
binary Bitbucket build Buildkite C#
...
85 tags
Values are sorted case-insensitively, so binary sorts near Bitbucket
rather than after ZIP.
JSON
Each command returns its values under a key named after the command, plus a count.
| Command | Shape |
|---|---|
tags |
{"tags": [...], "count": 85} |
languages |
{"languages": [...], "count": 32} |
filetypes |
{"filetypes": [...], "count": 76} |
$ panopticas languages --json | jq -r '.count'
32
These are useful for building a filter UI, or for diffing two releases to see what a version bump added:
$ panopticas tags --json | jq -r '.tags[]' > tags-new.txt
$ diff tags-old.txt tags-new.txt