fjs is the FunctionalScript command-line tool. It is invoked directly via Node:
node ./fjs/module.mjs <command> [args]or via npx without a global install:
npx functionalscript <command> [args]npx resolves the package name, not the bin name: fjs is an unrelated
package on npm, so npx fjs … would run somebody else's code.
or, once the package is installed globally:
fjs <command> [args]| Command | Description | Documentation |
|---|---|---|
test |
Run the FunctionalScript test suite | emergent_testing |
compile |
Compile a FunctionalScript module to JavaScript or JSON | djs, fsc |
cas |
Content-addressable storage operations (add, get, list) |
cas |
mcp |
Run an MCP server over stdio exposing the CAS and Evo as tools | mcp |
ci |
Generate the GitHub Actions CI workflow | ci |
web |
Serve a directory over HTTP | web |
run |
Run a FunctionalScript module as a program | below |
help |
Print available commands |
Each command also accepts a short alias (fjs t for fjs test, and so on).
fjs help prints them; this documentation uses the full names throughout.
fjs compile <input> <output>The output extension picks the format: .json emits a tree (shared values are
expanded), anything else emits a JavaScript module that preserves sharing by
naming reused values as consts. Imports are resolved and inlined in both
cases. See djs/README.md for the accepted subset.
fjs cifjs ci runs the built-in CI generator from fjs/ci/module.f.mjs, writing
.github/workflows/ci.yml. It is the standard entry point for projects that want
FunctionalScript's default workflow. Projects with custom CI setup code should keep
using fjs run <custom-ci-module>, so their module can call ci(setup) with its own
extra runtime steps.
fjs web [root] [port]
Serves root (default .) over HTTP on port (default 8080), mapping each
request path to a file under it — enough to open the pages this repository
generates in a browser, where a file:// URL has no origin. It binds loopback,
so what it serves stays on the machine it runs on. Both arguments are
positional; port becomes --port, and --host becomes possible at all, once
fjs/cli has named options.
fjs web # serve the working directory on http://127.0.0.1:8080/
fjs web docs 3000 # serve ./docs on http://127.0.0.1:3000/
Details, and the list of what it deliberately does not do, are in web.
fjs run <module> [args...]fjs run dynamically imports <module> and calls its main export as a
NodeProgram:
(v.main as NodeProgram)({ ...options, args })A module intended to be run with fjs run must export a named main constant
of type NodeProgram:
import type { NodeProgram } from '../effects/node/types.ts'
export const main: NodeProgram = options => {
// options.args — command-line arguments passed after the module path
...
}This mirrors:
export const proof— the convention for proof/test modules.mainentry-point naming from C, C++, and Rust.fjs/module.f.mjsitself, which usesexport const main.
Any arguments after <module> are forwarded to main via options.args:
fjs run ./my-tool.f.mjs foo bar # options.args === ['foo', 'bar']fjs/module.mjs — Node.js entry point (runs main via the node runner)
fjs/module.f.mjs — FunctionalScript command dispatcher (Commands list + dispatch)
fjs/cli/module.f.mjs — generic dispatch primitive (Command/Commands types in fjs/cli/types.ts)