GXFS gives agents Unix-like CLI commands for shared virtual filesystem content.
It is designed for internal docs and other project knowledge that should be
queried like a local docs/ directory, while being served from a backend store.
The project has two binaries:
gxfs-server: HTTP server that owns backend access.gxfs: thin CLI client used by agents and humans.
The CLI never connects to the database directly. It reads .gxfs/settings.toml,
talks to gxfs-server, and prints file-system-like output.
Build the binaries:
go build ./cmd/gxfs
go build ./cmd/gxfs-serverCreate a CLI config and agent instructions in the current project:
./gxfs initBy default this creates .gxfs/settings.toml and injects GXFS usage instructions
into AGENTS.md. To target Claude Code instead:
./gxfs init --agent claude
# or, for backwards compatibility:
./gxfs init --claudeTo create only the config file without touching agent instruction files:
./gxfs init --no-instructionsStart the server with a server config:
GXFS_SERVER_CONFIG=conf/server.toml ./gxfs-serverUse the CLI with a project config:
GXFS_CONFIG=.gxfs/settings.toml ./gxfs tree /docs -L 3
GXFS_CONFIG=.gxfs/settings.toml ./gxfs grep "auth" /docs
GXFS_CONFIG=.gxfs/settings.toml ./gxfs cat /docs/README.mdIf GXFS_CONFIG is not set, the CLI reads .gxfs/settings.toml. If
GXFS_SERVER_CONFIG is not set, the server reads conf/server.toml.
Example .gxfs/settings.toml:
repo = "github.com/user/repo"
[server]
addr = "http://127.0.0.1:7635"
[mount]
include = ["/"]
[docs]
path = "/docs"Fields:
repo: logical repository name. This must match a repo configured on the server.server.addr: gxfs-server base URL.mount.include: visible path prefixes for the CLI. Defaults to["/"].docs.path: default documentation root used in generated agent instructions. Defaults to/docs.
CLI config must not contain backend credentials.
Example conf/server.toml using PostgreSQL:
addr = "127.0.0.1:7635"
[[repos]]
name = "github.com/user/repo"
[repos.backend]
type = "postgres"
[repos.backend.postgres]
dsn = "${GXFS_POSTGRES_DSN}"
schema = "public"
nodes_table = "vfs_nodes"
content_table = "vfs_content"
repo_nodes_table = "vfs_repo_nodes"
cache_ttl = "30s"
[repos.backend.postgres.files]
path_column = "path"
kind_column = "kind"
size_column = "size"
mtime_column = "updated_at"Notes:
- Environment variables in config files are expanded.
- A server can configure multiple repos. Requests route by the
/v1/repos/{repo}/...path segment to the matching repo backend. - PostgreSQL schema is auto-migrated on server startup. Missing GXFS tables are
created with
CREATE TABLE IF NOT EXISTS. cache_ttlis optional. If omitted, the Postgres adapter keeps each repo's loaded tree until writes/deletes invalidate it or the process restarts.
List and inspect:
gxfs ls /docs
gxfs ls -la /docs
gxfs tree /docs -L 3
gxfs stat /docs/guide.md
gxfs stat -f /docs/guide.mdRead content:
gxfs cat /docs/guide.md
gxfs cat -n /docs/guide.md
gxfs cat -b /docs/guide.mdSearch content:
gxfs grep "database" /docs
gxfs grep -i "database" /docs
gxfs grep -E "db|database" /docs
gxfs grep -C 2 "migration" /docs
gxfs grep --include "*.md" --exclude "archive/*" "token" /docs
gxfs grep -l "TODO" /docs
gxfs grep -c "TODO" /docsFind paths:
gxfs find /docs --name "*.md"
gxfs find /docs --iname "*readme*"
gxfs find /docs --type f --maxdepth 3 --name "*.md"
gxfs find /docs --type d --name "api"Write, edit, and delete:
gxfs write /docs/new.md "# New Doc"
cat local.md | gxfs write /docs/local.md
gxfs edit /docs/new.md --old "New" --new "Updated"
gxfs edit /docs/new.md --old "foo" --new "bar" --all
gxfs delete /docs/new.md
gxfs delete /docs/old-sectionSync local docs into GXFS:
gxfs sync push docs
gxfs sync pull docs
gxfs sync pull docs --materialize
gxfs refresh docs
gxfs materialize docs
gxfs dematerialize docs
gxfs sync push docs --manifest .gxfs/manifest.tomlgxfs ls [path]
-l, --long: long listing format.-a, --all: show hidden files.-R, --recursive: list recursively.-d, --directory: show the directory itself instead of its contents.-t, --sort-time: sort by modification time, newest first.-S, --sort-size: sort by size, largest first.-r, --reverse: reverse sort order.-F, --classifyor-p, --slash: append directory indicators.
gxfs tree [path]
-L, --level: maximum tree depth. Default is2.-a, --all: show hidden files.-d, --dirs-only: list directories only.-f, --full-path: print full path prefix.-s, --size: show file sizes.-t, --sort-time: sort by modification time.--dirsfirst: list directories before files.
gxfs cat <path>
-n, --number: number all output lines.-b, --number-nonblank: number non-blank output lines.-s, --squeeze-blank: squeeze repeated blank lines.
gxfs grep <pattern> [path]
-E, --regex: treat pattern as a regular expression.-i, --ignore-case: case-insensitive search.-v, --invert-match: show non-matching lines.-w, --word-regexp: match whole words.-x, --line-regexp: match whole lines.-A, --after-context: lines of trailing context.-B, --before-context: lines of leading context.-C, --context: lines of context before and after.-l, --files-with-matches: print only file names.-c, --count: print match counts per file.-o, --only-matching: print only matched text for literal searches.--include: only search matching file globs.--exclude: skip matching file globs.-a, --all: search hidden files.
gxfs find [path]
--name: filename glob.--iname: case-insensitive filename glob.-t, --type: filter by type,forfilefor files,dordirfor dirs.--maxdepth: maximum descent depth.0means unlimited.--mindepth: minimum descent depth.-a, --all: include hidden files.
gxfs stat <path>
-f, --terse: single-line output.-c, --format: custom format string.
Format placeholders:
%n: name%p: path%k: kind%s: size%y: modification time%m: metadata%%: literal percent sign
gxfs write <path> [content]
Creates or overwrites a file. Parent directories are created as needed. If
content is omitted, content is read from stdin.
gxfs edit <path> --old <text> --new <text> [--all]
Replaces text in a file. By default only the first occurrence is replaced.
Use --all to replace every occurrence.
gxfs delete <path>
Deletes a file or directory. Directory deletes are recursive.
gxfs init [path]
Creates .gxfs/settings.toml and, unless disabled, injects GXFS instructions
into an agent instruction file.
- default: write
AGENTS.md --agent claude: writeCLAUDE.md--claude: alias for--agent claude--no-instructions: write config only
The injected block is wrapped with:
<!-- GXFS_START -->
...
<!-- GXFS_END -->Running gxfs init again replaces the existing block instead of appending a
duplicate.
gxfs sync push <local-path>
Scans a local file or directory, uploads each file through the existing GXFS
write API, and updates .gxfs/manifest.toml.
--manifest: custom manifest path. Defaults to.gxfs/manifest.toml.
Phase 2A/2B stores client-computed sha256:<hex> hashes, file size, and mtime
in the manifest. It does not change the server API or database schema.
gxfs sync pull <local-path>
Reads remote GXFS docs under the given path and updates .gxfs/manifest.toml.
By default it only refreshes the manifest; it does not write local files.
--manifest: custom manifest path. Defaults to.gxfs/manifest.toml.--materialize: write pulled docs to local files.--force-local: resolve conflicts by pushing local content back to GXFS.--force-remote: resolve conflicts by accepting remote content locally.
Conflict detection compares the manifest's last synced hash with current local and remote hashes. If both changed, pull fails unless one force flag is used.
gxfs refresh <path>
Refreshes .gxfs/manifest.toml for remote docs under a path without writing
local files.
--manifest: custom manifest path. Defaults to.gxfs/manifest.toml.
gxfs materialize <path>
Refreshes the manifest and writes remote docs under the path to local markdown files.
--manifest: custom manifest path. Defaults to.gxfs/manifest.toml.
gxfs dematerialize <path>
Marks manifest entries under the path as remote-only and removes local materialized files.
--manifest: custom manifest path. Defaults to.gxfs/manifest.toml.--keep-files: update the manifest but leave local files in place.
For agent workflows, treat GXFS as the canonical way to browse shared project docs. Prefer:
gxfs tree /docs -L 3
gxfs grep "topic" /docs
gxfs cat /docs/file.mdover scanning local files when the information is meant to come from shared
internal documentation. The default docs root is /docs, configurable through
[docs].path in .gxfs/settings.toml.
Run tests:
go test ./...Run Postgres e2e tests:
go test -count=1 -tags=e2e ./e2eBuild:
go build ./cmd/gxfs
go build ./cmd/gxfs-serverKey packages:
cmd/gxfs: Cobra CLI commands.cmd/gxfs-server: HTTP server entrypoint.internal/client: HTTP client that implements the store adapter interface.internal/server: HTTP API handler.internal/store: shared adapter interfaces and request/response types.internal/store/postgres: PostgreSQL adapter and embedded migrations.internal/vfs: in-memory tree semantics used by adapters.