Skip to content

Commit 4508936

Browse files
authored
Merge pull request #312 from aaronsb/feature/fuse-multi-command-cli
feat: multi-command CLI for kg-fuse
2 parents 1fc2a08 + 1a3f658 commit 4508936

12 files changed

Lines changed: 2980 additions & 242 deletions

File tree

fuse/README.md

Lines changed: 132 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Knowledge Graph FUSE Driver
22

3-
Mount the knowledge graph as a filesystem.
3+
Mount the knowledge graph as a filesystem. Browse ontologies, search concepts by creating directories, read documents — all through your file manager or terminal.
44

55
## Installation
66

@@ -13,7 +13,7 @@ sudo apt install fuse3 # Debian/Ubuntu
1313
sudo dnf install fuse3 # Fedora
1414
```
1515

16-
**kg CLI** (for OAuth setup):
16+
**kg CLI** (for authentication setup):
1717
```bash
1818
npm install -g @aaronsb/kg-cli
1919
```
@@ -24,89 +24,173 @@ npm install -g @aaronsb/kg-cli
2424
pipx install kg-fuse
2525
```
2626

27-
### Upgrade
27+
## Quick Start
2828

2929
```bash
30-
pipx upgrade kg-fuse
30+
# 1. Authenticate with the knowledge graph
31+
kg login
32+
kg oauth create
33+
34+
# 2. Set up a FUSE mount (interactive — detects auth, validates path, offers autostart)
35+
kg-fuse init /mnt/knowledge
36+
37+
# 3. Mount
38+
kg-fuse mount
3139
```
3240

33-
## Setup
41+
That's it. Browse `/mnt/knowledge/` in your file manager or terminal.
3442

35-
Create OAuth credentials (one-time):
43+
## Commands
3644

37-
```bash
38-
kg oauth create --for fuse
45+
```
46+
kg-fuse Status of running mounts + help summary
47+
kg-fuse init [mountpoint] Interactive setup: detect auth, configure mount, offer autostart
48+
kg-fuse mount Fork daemons for ALL configured mounts
49+
kg-fuse mount /mnt/knowledge Fork daemon for just this one
50+
kg-fuse mount /mnt/knowledge -f Run in foreground (for debugging)
51+
kg-fuse unmount Kill all kg-fuse daemons, clean unmount
52+
kg-fuse unmount /mnt/knowledge Kill just this one
53+
kg-fuse status Same as bare kg-fuse
54+
kg-fuse config Show configuration with masked secrets
55+
kg-fuse repair Detect and fix orphaned mounts, stale PIDs, bad config
56+
kg-fuse update Self-update via pipx
3957
```
4058

41-
This writes credentials to `~/.config/kg-fuse/config.toml`.
59+
Bare `kg-fuse` with no arguments shows mount status, daemon process info, API connectivity, and other FUSE mounts on the system.
4260

43-
## Usage
61+
## Configuration
4462

45-
```bash
46-
# Mount (reads credentials from config)
47-
kg-fuse /mnt/knowledge
63+
### File layout
4864

49-
# Or run in foreground for debugging
50-
kg-fuse /mnt/knowledge -f
51-
```
65+
| File | Owner | Purpose |
66+
|------|-------|---------|
67+
| `~/.config/kg/config.json` | kg CLI | Auth credentials, API URL (kg-fuse reads only) |
68+
| `~/.config/kg/fuse.json` | kg-fuse | Mount definitions, per-mount preferences |
69+
| `~/.local/share/kg-fuse/mounts/<id>/queries.toml` | kg-fuse | Saved query directories per mount |
70+
| `~/.local/state/kg-fuse/<id>.pid` | kg-fuse | Daemon PID files |
5271

53-
Unmount:
72+
kg-fuse **never writes** to kg CLI's `config.json` — it only reads auth credentials from it. This isolates failures: a bug in kg-fuse can only damage `fuse.json`, never your kg CLI config.
5473

55-
```bash
56-
fusermount -u /mnt/knowledge
57-
# or just Ctrl+C if running in foreground
58-
```
74+
### Credential resolution
5975

60-
### Manual Credentials
76+
Priority (highest to lowest):
77+
1. CLI flags (`--client-id`, `--client-secret`)
78+
2. `fuse.json` `auth_client_id` → lookup in `config.json` auth
79+
3. `config.json` auth section directly
80+
4. Error with guidance to run `kg login` + `kg oauth create`
6181

62-
You can also pass credentials directly:
82+
### Example fuse.json
6383

64-
```bash
65-
kg-fuse /mnt/knowledge \
66-
--api-url https://kg.example.com/api \
67-
--client-id YOUR_CLIENT_ID \
68-
--client-secret YOUR_SECRET
84+
```json
85+
{
86+
"auth_client_id": "kg-cli-admin-ba93368c",
87+
"mounts": {
88+
"/mnt/knowledge": {
89+
"tags": { "enabled": true, "threshold": 0.5 },
90+
"cache": { "epoch_check_interval": 5.0, "content_cache_max": 52428800 },
91+
"jobs": { "hide_jobs": false }
92+
}
93+
}
94+
}
6995
```
7096

7197
## Filesystem Structure
7298

7399
```
74100
/mnt/knowledge/
75-
├── ontology-a/ # Each ontology is a directory
76-
│ ├── doc1.md # Documents in that ontology
77-
│ └── doc2.md
78-
└── ontology-b/
79-
└── doc3.md
101+
├── ontology/ # System-managed ontology listing
102+
│ ├── ontology-a/
103+
│ │ ├── documents/ # Source documents (read-only, write to ingest)
104+
│ │ │ ├── doc1.md
105+
│ │ │ └── image.png
106+
│ │ └── my-query/ # User query scoped to this ontology
107+
│ │ ├── concept1.concept.md
108+
│ │ ├── concept2.concept.md
109+
│ │ ├── images/ # Image evidence from matching concepts
110+
│ │ └── .meta/ # Query control plane
111+
│ └── ontology-b/
112+
│ └── documents/
113+
└── my-global-query/ # User query across all ontologies
114+
└── *.concept.md
115+
```
116+
117+
### Query directories
118+
119+
Create a directory → it becomes a semantic search:
120+
121+
```bash
122+
mkdir /mnt/knowledge/ontology/my-ontology/leadership
123+
ls /mnt/knowledge/ontology/my-ontology/leadership/
124+
# → concept files matching "leadership" within that ontology
125+
126+
mkdir /mnt/knowledge/machine-learning
127+
ls /mnt/knowledge/machine-learning/
128+
# → concept files matching "machine learning" across all ontologies
80129
```
81130

82-
### Read: Browse Documents
131+
### Query control plane (.meta)
132+
133+
Each query directory has a `.meta/` subdirectory for tuning:
83134

84135
```bash
85-
ls /mnt/knowledge/ # List ontologies
86-
ls /mnt/knowledge/my-ontology/ # List documents
87-
cat /mnt/knowledge/my-ontology/doc.md # Read document
136+
cat .meta/threshold # Read current threshold (0.0-1.0)
137+
echo 0.3 > .meta/threshold # Lower threshold for broader matches
138+
echo 100 > .meta/limit # Increase result limit
139+
echo "noise" >> .meta/exclude # Filter out a term
140+
echo "AI" >> .meta/union # Broaden with additional term
88141
```
89142

90-
### Write: Ingest Documents (future)
143+
### Write: Ingest documents
144+
145+
```bash
146+
cp report.pdf /mnt/knowledge/ontology/my-ontology/documents/
147+
# File enters the ingestion pipeline → extracts concepts → links to graph
148+
```
149+
150+
## Autostart
151+
152+
`kg-fuse init` offers to set up autostart:
91153

154+
- **Systemd** (preferred): installs a user service at `~/.config/systemd/user/kg-fuse.service`
155+
- **Shell RC** (fallback): adds `kg-fuse mount` to `.bash_profile`, `.zshrc`, or fish config
156+
157+
Manage systemd service:
92158
```bash
93-
cp report.pdf /mnt/knowledge/my-ontology/
94-
# File "disappears" into ingestion pipeline
95-
# Creates job, extracts concepts, links to graph
159+
systemctl --user status kg-fuse
160+
systemctl --user restart kg-fuse
161+
journalctl --user -u kg-fuse -f
96162
```
97163

164+
## Safety
165+
166+
kg-fuse includes several safety checks:
167+
168+
- **Mountpoint validation**: refuses system paths (`/home`, `/etc`, etc.) and non-empty directories
169+
- **FUSE collision detection**: checks for existing FUSE mounts (rclone, SSHFS, etc.) at the target path
170+
- **Config isolation**: kg-fuse writes only to `fuse.json`, never to kg CLI's `config.json`
171+
- **Atomic config writes**: `fuse.json` updates use temp file + rename for crash safety
172+
- **PID verification**: before killing a daemon, verifies it's actually a kg-fuse process via `/proc/cmdline`
173+
- **Orphan recovery**: `kg-fuse repair` detects dead mounts ("transport endpoint not connected") and cleans up
174+
- **RC file safety**: shell config changes use delimited blocks with backups
175+
98176
## Debug Mode
99177

100178
```bash
101-
kg-fuse /mnt/knowledge --debug -f
179+
kg-fuse mount /mnt/knowledge -f --debug
180+
```
181+
182+
Runs in foreground with verbose logging. Daemon logs are also available at:
183+
```
184+
~/.local/share/kg-fuse/mounts/<mount-id>/daemon.log
102185
```
103186

104187
## Architecture
105188

106-
The FUSE driver is an independent client that:
107-
- Authenticates via OAuth (like CLI, MCP server)
108-
- Makes HTTP requests to the API server
109-
- Caches directory listings (30s TTL)
110-
- Defaults to `localhost:8000` if unconfigured (fail-safe: won't accidentally query external endpoints)
189+
The FUSE driver is an independent Python client that:
190+
- Authenticates via OAuth (shared credentials with kg CLI)
191+
- Makes HTTP requests to the knowledge graph API
192+
- Uses epoch-gated caching for directory listings (background refresh, not fixed TTL)
193+
- Persists user query directories in client-side TOML files
194+
- Runs as a daemonized process per mount point
111195

112-
See ADR-069 for full design rationale.
196+
See [ADR-069](../docs/architecture/ADR-069-fuse-filesystem-driver.md) for design rationale.

0 commit comments

Comments
 (0)