GitHub
issues, PRs, CI, and repo trees
/github/ollama/ollama/issues/open/2853/title
reposissuesPRsCI runsrepo tree
omnifs lets you access the world through your filesystem. APIs and data sources become files and directories you can ls, cat, grep, pipe, and hand to an agent.
APIs let us program against services, but each one is a world of its own. Schemas, auth, pagination, errors, rate limits. Agents pay the complexity tax in tokens.
In contrast, the filesystem is the most durable interface in computing. Every program, agent, language masters disk and file I/O. Semantics are strict and universally understood, and /filesystem/paths offer hierarchical addressing.
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
request: { retries: 3 },
})
const issues = await octokit.paginate(
octokit.rest.issues.listForRepo,
{ owner, repo, state: "open" },
)
return issues
.filter((i) => !i.pull_request)
.map((i) => i.title) s3 = boto3.client("s3")
keys = []
paginator = s3.get_paginator("list_objects_v2")
try:
for page in paginator.paginate(
Bucket=bucket, Prefix=prefix):
for o in page.get("Contents", []):
keys.append(o["Key"])
except ClientError as e:
raise RuntimeError(e.response["Error"]["Code"])
return keys cli, err := client.NewClientWithOpts(
client.FromEnv)
if err != nil {
return false, err
}
defer cli.Close()
info, err := cli.ContainerInspect(
context.Background(), id)
if err != nil {
return false, fmt.Errorf("inspect: %w", err)
}
return info.State.Running, nil /omnifs mounts systems, services, and data sources (really, anything) onto the local filesystem. One stable interface replaces a client per service: files and directories you address by path.
One daemon, three axes: how the namespace is exposed, where it runs, and which providers it mounts. Pick across them and the setup command writes itself.
$omnifs setup --frontend fuse --mode host --providers github,dnsProviders are the extension point. If a system has an API, socket, repository, database, object store, or control plane, it can have a path. Each translates its service into directories, files, fields, rendered views, and searchable trees.
issues, PRs, CI, and repo trees
/github/ollama/ollama/issues/open/2853/title
reposissuesPRsCI runsrepo tree
records over DNS-over-HTTPS, dig without dig
/dns/example.com/MX
AAAAAMXNSTXT
the arXiv corpus, by id or search
/arxiv/papers/1706.03762/paper.json
papersmetadataPDFsourceversions
Docker daemon metadata through a host socket
/docker/containers/by-name/postgres/state
containersstatesystem
teams, issues, state, and descriptions
/linear/teams/ENG/issues/open/ENG-1421/state
teamsissuesstateprioritydescription
a read-only SQLite database
/db/tables/Album/schema.sql
schemastablessample rows
Models, datasets, and Spaces, mounted as files.
Pods, services, and nodes, read like a tree.
Buckets and objects, browsed as directories.
Channels, threads, and messages you can grep.
Guilds, channels, and messages, walked as paths.
Keys, values, and streams at your fingertips.
Customers, charges, and invoices, projected as files.
Zones, DNS records, and Workers, read as paths.
Threads, messages, and labels, mounted as files.
Files and folders, mirrored as directories.
Projects, deployments, and logs, walked as paths.
Chats, channels, and messages, read as files.
Conversations and messages, mounted as files.
Models, files, and runs, read as paths.
Pages, databases, and blocks, walked as a tree.
Once services share a filesystem substrate, pipes can cross system boundaries. Read a CI run, inspect a container, grep the ticket queue, or sketch new providers for the systems you wish were files.
# provider sketch $ cat /cloudflare/zones/0xff.ai/firewall/events/latest/client_ip \ | xargs -I% cat /dns/reverse/% census-12.shodan.io
# sketched Slack path, live GitHub issue leaf $ cat /slack/channels/incidents/@last/metadata/release_issue \ | xargs -I% cat /github/0xff-ai/api/issues/all/%/user release-owner@0xff.ai
# live arxiv, sketched huggingface $ cat /arxiv/papers/1706.03762/paper.json | jq -r .title Attention Is All You Need $ grep -l 1706.03762 /huggingface/models/*/*/README.md /huggingface/models/google-t5/t5-base/README.md
# sketched Stripe path, live db leaf $ cat /stripe/charges/ch_3PqZ8/metadata/order_id \ | xargs -I% cat /db/tables/orders/%/data.json | jq -r .status paid
Providers run sandboxed with no ambient authority, reaching the outside only through capability-gated callouts the host runs, so the gate, the cache, and the trace are one boundary. Read the architecture.
A provider teaches omnifs how one system appears as paths.
You own the routes, object identity, and rendering. The host owns FUSE, credentials, cache, and callouts.
use omnifs_sdk::{browse::FileContent, prelude::*};
#[omnifs_sdk::object(kind = "github.issue", key = IssueKey)]
#[derive(Clone, Serialize, Deserialize)]
struct Issue { title: String, state: String, body: String }
impl Issue {
fn title(&self) -> Result<FileContent> { Ok(FileContent::new(self.title.as_bytes())) }
fn state(&self) -> Result<FileContent> { Ok(FileContent::new(self.state.as_bytes())) }
fn body(&self) -> Result<FileContent> { Ok(FileContent::new(self.body.as_bytes())) }
}
#[path_captures]
struct IssueKey { owner: OwnerName, repo: RepoName, filter: Facet<StateFilter>, number: u64 }
impl Key for IssueKey {
type Object = Issue;
type State = State;
async fn load(&self, cx: &Cx<State>, since: Option<Validator>) -> Result<Load<Issue>> {
load_issue(cx, self, since).await
}
}
#[omnifs_sdk::provider(
metadata = "omnifs.provider.json",
resources(endpoints = [api::GitHubApi], git = true),
)]
impl GithubProvider {
type Config = Config;
type State = State;
fn start(_cfg: Config, r: &mut Router<State>) -> Result<State> {
r.object::<Issue>("/{owner}/{repo}/issues/{filter}/{number}", |o| {
o.representations("item", (Markdown,))?;
o.file("title").project(Issue::title)?;
o.file("state").project(Issue::state)?;
o.file("body").lazy().project(Issue::body)?;
Ok(())
})?;
Ok(State::default())
}
} Plan 9 made every resource a file reached through a tiny, uniform set of operations, served by a file server per resource. omnifs keeps the idea and swaps the 1990s mechanics for a sandboxed Wasm and FUSE stack, capability-gated callouts, and today's services.
Open source under MIT OR Apache-2.0. If you would rather cat a path than learn another SDK, or you are shipping a provider against omnifs:provider@0.4.0, say hello.