Skip to content

Repository files navigation

fspath

Code as a tree, not as text. fspath is an in-memory AST that you manipulate through filesystem-like path operations — no syntax, no parsing, no formatting. Write nodes, transpile to code.

Built for agents and tools that need to generate code without the brittleness of string templates. The name says it: filesystem paths become programs.

Why fspath?

Generating code as strings is fragile. Miss a semicolon, mismatch a bracket, forget indentation — and everything breaks. fspath fixes this by representing code as a typed tree. Each path encodes both structure and type. The transpiler walks the tree and emits valid code in your target language. It's impossible to produce a syntax error in the tree format.

This is the Go community edition. An Erlang/OTP enterprise edition (fspath-beam) adds persistence, actor-model concurrency, and horizontal scale.

Quick Example

write_node("/src/greet.fn/params/name.param/type", "string")
write_node("/src/greet.fn/return_type", "string")
write_node("/src/greet.fn/body/0.return/expr/msg.binop", "+")
write_node("/src/greet.fn/body/0.return/expr/msg.binop/left.literal", "\"Hello, \"")
write_node("/src/greet.fn/body/0.return/expr/msg.binop/right.ident", "name")

Transpiles to:

func greet(name string) string {
  return ("Hello, " + name)
}

Or JavaScript, or Lua. Same tree, three languages.

What It Does

  • Three target languages: JavaScript, Lua, Go — same tree, different output
  • Go is the strongest target: structs, methods, interfaces, goroutines, channels, select, for-range, defer, type assertions, composite literals, typedefs
  • JavaScript is solid: functions, closures, if/else chains, loops, ternary, arrow functions, template literals, ES modules
  • MCP server: agents can call write_node, read_node, list_children, transpile, delete_node, save_tree, load_tree directly
  • HTTP API: same operations over REST, for non-MCP clients
  • Insertion-order tree: parameters and struct fields preserve the order you wrote them
  • Persistence: save/load trees to/from JSON files
  • Zero dependencies: pure Go stdlib, single binary

Languages by Maturity

Feature JavaScript Lua Go
Functions, params, returns
Variables, assignments
If/else/else-if
While loops ✅ (emits for)
For loops
Binary/unary operators
Function calls
Anonymous functions
Structs, methods
Interfaces
Goroutines, channels ✅¹ ✅¹
Select statements
For-range
Defer ✅² —³
Type definitions
Composite literals
Imports
module.exports

¹ JS uses async IIFE, Lua uses coroutine.wrap — idiomatic, not semantically equivalent to goroutines. ² JS uses try/finally pattern — runs immediately, not at function exit like Go defer. ³ Lua has no try/finally equivalent — deferred expressions emitted as comments.

Getting Started

Build

go build -o fspath .

Run as HTTP Server

./fspath -port 8080

Endpoints:

  • GET /read?path= — Read node value
  • POST /write?path= — Write node value (body = value)
  • GET /list?path= — List children
  • DELETE /delete?path= — Delete node and descendants
  • POST /move?source=&dest= — Move subtree
  • POST /copy?source=&dest= — Copy subtree
  • GET /transpile?lang=go — Transpile to JS (default), Lua, or Go
  • GET /tree — Dump entire tree as JSON
  • POST /save?path= — Save tree to JSON file
  • POST /load?path= — Load tree from JSON file

Run as MCP Server

./fspath -mcp

MCP tools: read_node, write_node, list_children, delete_node, move_node, copy_node, transpile, export_tree, save_tree, load_tree

Run Tests

go test ./...                    # All tests
go test -run 'TestGo' ./...     # Go transpiler only
go test -run 'TestLua' ./...    # Lua transpiler only
go test -run 'TestJS' ./...     # JS transpiler only

Architecture

tree.go         (~225 lines)  — In-memory tree: Read, Write, ListChildren, Delete, Move, Copy
transpiler.go   (~2710 lines) — Walks tree → emits JS/Lua/Go
mcp.go          (~410 lines)  — MCP stdio server for agent integration
http.go         (~427 lines)  — HTTP REST API
export.go       (~120 lines)  — Export helpers
persist.go      (~141 lines)  — JSON save/load
validate.go     (~142 lines)  — Tree validation
main.go         (~68 lines)   — Entry point (HTTP or MCP mode)

Tree Format Quick Reference

Every node is a path. The path encodes both structure and type:

/src/functionname.fn                    — Function declaration
/src/StructName.struct                  — Struct declaration
/src/fn.fn/params/name.param/type       — Typed parameter
/src/fn.fn/return_type                  — Return type (Go)
/src/fn.fn/body/0.return/expr/x.ident   — Return statement
/src/fn.fn/body/0.decl/name.ident       — Variable declaration
/src/fn.fn/body/0.for/init.decl/...     — For loop init
/src/fn.fn/body/0.if/condition.expr/... — If condition

Type suffixes (.fn, .struct, .ident, .binop, etc.) tell the transpiler what kind of node it is. Structural names (left, right, body, condition, etc.) tell it where things go.

See docs/architecture/tree-format.md for the complete reference with all 46+ node types.

Documentation

Known Limitations

These are real. They affect real use:

  • No import inference: Go output needs import blocks, but the transpiler won't figure out which imports you need. Add them manually via /src/imports/0.
  • Multi-target reassignment doesn't work: data, err = expr (reassignment) can't be expressed. Only data, err := expr (declaration) works. Use .raw for reassignment.
  • No error handling constructs: No try/catch for JS, no panic/recover for Go.
  • Struct field order is sorted alphabetically by name: The tree preserves insertion order for most things, but struct fields render alphabetically.
  • Self-hosting doesn't work yet: The transpiler can generate Go, but it can't yet generate itself with perfect fidelity. This is a long-term goal.

Community Edition

This is the Go community edition of fspath. It's a complete, usable transpiler designed for agents and tools that need to generate code through tree manipulation.

For persistence, actor-model concurrency, and horizontal scale, see fspath-beam (Erlang/OTP).

License

FSL-1.1-MIT — Functional Source License with MIT Future License.

You can use, modify, and redistribute this software for any purpose except building a competing product or service. Two years after each release, the code for that release converts to MIT license.

See LICENSE for full terms.

About

Code as a tree, not as text. In-memory AST manipulated through filesystem-like path operations. Built for agents and tools that generate code without string templates. Transpiles to JavaScript, Lua, Go.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages