No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Justine Akehurst 9f9471f7e6
All checks were successful
CI / check (push) Successful in 1m35s
Add vision and plugin architecture blueprints
Record what this project is for, which until now existed only in conversation.
fname is a spiritual prequel to archivist: point it at a file or a directory,
and it derives a name from the file's own contents and renames in place. No
repository, no database, nothing to migrate away from.

Naming runs in four stages — identify by magic value, extract with a
per-filetype plugin, fill remaining gaps with a local LLM, then apply a
per-type template. Deterministic extraction always runs first; a PDF with an
embedded title never triggers an inference. The LLM configuration follows the
homelab paperless-ngx precedent, including the constraints that make it work:
qwen3:4b-instruct because 4b fits a shared 6 GB card and the -instruct suffix
avoids a <think> block that breaks JSON parsing, and an 8192 context that must
match the server or get truncated silently.

Per-type templates give consistency within a filetype without forcing PDFs and
MP3s to agree with each other. The convention's grammar stays fixed; only the
description field varies by type.

Scope is stated as commitments rather than ambitions, so the document can
settle an argument later: one user, no repository, no database of record, no
hosted inference, no plugin may rewrite the convention, no metadata written
into files, no destructive rename. v1.0 is PDFs and ID3-tagged audio, both as
plugins — two types because one could be hard-coded and would teach nothing
about whether the plugin boundary sits in the right place.

The plugin architecture document records the boundaries the existing code
already enforces, including why each rule exists rather than only what it does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XhA69mkFRwmkhrDvRsQLW
2026-08-16 22:53:49 -07:00
.forgejo License under AGPL-3.0-or-later and adopt the archivist tooling 2026-08-16 21:41:37 -07:00
blueprints Add vision and plugin architecture blueprints 2026-08-16 22:53:49 -07:00
src/fname Add rich output and a pluggy plugin system 2026-08-16 22:08:42 -07:00
tests Add rich output and a pluggy plugin system 2026-08-16 22:08:42 -07:00
.gitignore License under AGPL-3.0-or-later and adopt the archivist tooling 2026-08-16 21:41:37 -07:00
.license-header.txt License under AGPL-3.0-or-later and adopt the archivist tooling 2026-08-16 21:41:37 -07:00
.pre-commit-config.yaml License under AGPL-3.0-or-later and adopt the archivist tooling 2026-08-16 21:41:37 -07:00
.python-version first commit 2026-08-16 21:20:30 -07:00
CLAUDE.md Add rich output and a pluggy plugin system 2026-08-16 22:08:42 -07:00
LICENSE License under AGPL-3.0-or-later and adopt the archivist tooling 2026-08-16 21:41:37 -07:00
pyproject.toml Add rich output and a pluggy plugin system 2026-08-16 22:08:42 -07:00
README.md License under AGPL-3.0-or-later and adopt the archivist tooling 2026-08-16 21:41:37 -07:00
uv.lock Add rich output and a pluggy plugin system 2026-08-16 22:08:42 -07:00

fname

Manage files whose metadata lives in their own names.

fname implements the filename-as-database convention documented by Karl Voit. Voit's stack is four separate tools glued by convention (date2name, appendfilename, filetags, move2archive); fname is one command with subcommands covering the same ground.

2014-05-09T22.19.58 Susan presenting her new shoes -- family clothing.jpg
└──────── timestamp ────────┘ └───── description ─────┘ └──── tags ────┘
Part Rule
Timestamp ISO 8601, colons replaced with dots so the name stays valid on Windows. Date-only is fine
Description Free text, spaces allowed
Separator -- (space, two hyphens, space)
Tags Lowercase, single words, space-separated, before the extension

Why the filename

Filenames survive every tool, backup, and platform migration. Embedded metadata such as EXIF gets stripped by tools that do not know to preserve it, and an external database dies with the application that owns it. The convention is the artifact: the files stay usable if fname disappears entirely.

Commands

Command Does
fname stamp Prepend a timestamp, from EXIF where available, else mtime
fname append Insert descriptive text between the timestamp and the tags
fname tag Add or remove tags, completing from a controlled vocabulary
fname move Move into the dated archive folder, prompting for an event name
fname find Filter by tag; materialize matches as a symlink view

find never mutates. Write commands are idempotent, so running one twice leaves the name unchanged, and they never destroy an existing description or tag set.

Status: early. The command surface is defined and the CLI parses, but the subcommands are not implemented yet.

Install

Requires Python 3.14 and uv.

$ git clone ssh://git@git.clowderlabs.com/justine/fname.git
$ cd fname
$ uv sync
$ uv run fname --help

Development

tox is the entry point; every gate CI runs is a tox environment, so a green run locally means a green build.

$ uv run tox              # license, lint, format, typecheck, pyright, test
$ uv run tox -e fix       # autofix lint findings, then format
$ uv run tox -e cov       # tests with the 95% coverage gate
$ uv run tox -e testmon   # only the tests affected by your change

Work starts as an issue, and every pull request links back to one with Closes #<n> or Ref #<n>. CI enforces the link.

Documentation

blueprints/ is an OKF v0.2 bundle holding the source material this project derives from: the workflow, the folder scheme, the tag rules, the tool-selection method, and the argument that motivates the whole approach. Start at blueprints/index.md.

License

GNU Affero General Public License v3.0 or later.

Copyright (c) 2026 Justine Akehurst.