Reference
Packages
A manifest, a resolver, a lockfile — and a ceiling on what a dependency may do, checked at compile time in every consumer.
A manifest
[package]
name = "ecommerce_cart"
version = "1.0.0"
entry = "main.gr"
capabilities = ["io", "net"]
[dependencies.json]
path = "../../packages/json"
version = "^1.0.0"
The ceiling
capabilities is the set of effects this package may perform.
Effects are inferred from source, so the claim is checked rather than trusted. A
dependency that starts reading files without declaring io fails to
build — and it fails in your build, not silently in theirs.
This is the part of the package system worth having. Version resolution is plumbing every language has; a supply chain where a dependency's reach is a compile-time fact is not.
Commands
grasm deps # resolve, check ceilings, write grasm.lock
grasm deps --locked # fail rather than update the lockfile
What ships today
660 libraries, all written inside this repository because there is no registry to get one from. The table below is a sample of them — the ones where the capability column says something worth reading.
| Package | Capabilities | What it is |
|---|---|---|
http | none | Requests, responses, routing with :param and * segments, percent decoding, HTML escaping. |
http_server | io, net | The accept loop, and many conversations on one thread. Depends on http. |
http_client | net | Dials, sends what http composed, reads until the declared frame arrives. Depends on http. |
json | none | Parse, render, reach into a document, build one. Six programs in ProjectGold/ depend on it. |
bytes_codec | none | Hex, base64, url-safe, constant-time compare. |
time | none | Civil calendar, ISO-8601, durations. The clock is a parameter. |
random | none | Seeded generator, uniform without modulo bias, shuffle. |
uuid | none | v4 and v7. The entropy is a parameter. |
path | none | Join, normalise, split, containment. Touches no disk. |
url | none | Parse, build, resolve, percent code, query strings. |
log | io, Log | Logging as an effect: a library that logs declares Log, not io. |
csv | none | Quoting, embedded newlines, headers, any separator. |
cli | none | Flags, bundles, subcommands, --, a generated help page. |
testing | none | Cases as values, table-driven suites, a golden diff that names the line and column. |
toml | none | Tables, arrays, inline tables, reached by dotted path. |
resilience | none | Backoff with full jitter, circuit breaker, token bucket, deadlines — the clock is a parameter. |
cache | none | Cache[V], least-recently-used with an expiry. |
crypto_hash | none | SHA-256, HMAC-SHA-256, PBKDF2, constant-time compare — every digest checked against FIPS 180-4, RFC 4231 and RFC 6070. |
regex | none | A Thompson machine, so matching is linear in the input for every pattern — (a+)+b against thirty as returns at once. |
fs | io | Walk, glob, copy, temporary paths. The arithmetic half is path, which declares nothing. |
jwt | none | HS256. The algorithm comes from the caller, never the token — so alg: none is refused because it disagrees, not by a special case. |
cors | none | A request in, the headers a response needs out. |
dotenv | io | .env files. It answers a map and never touches the process environment. |
sanitize | none | Escaping by destination — HTML text, an attribute, a script block, a URL, a shell argument, a header. There is no general escape, because there is no such thing. |
metrics | Metric | Counters, gauges, histograms and the Prometheus text format — the registry is an effect, so a library that counts declares Metric and not io. |
errors | none | A failure carrying its cause, its place and its fields. Grasm has no captured backtrace, so every link is one somebody wrote — which is the work, and is why nothing is lost. |
trace | Trace | Spans and W3C traceparent, as an effect. An all-zero trace id is refused, since a receiver that accepts one joins every unrelated request into a single trace. |
redis | net | RESP2 and RESP3 both — a client that reads only one refuses half the servers it meets. The encoder and decoder are pure, so the demo drives them with bytes and never opens a socket. |
websocket | none | The upgrade handshake (checked against RFC 6455's own example) and the frame format. A frame's masking is checked in both directions, because a server that accepts an unmasked one sits behind a proxy that can be poisoned. ws:// only — there is no TLS. |
password | none | PBKDF2-HMAC-SHA256. The stored form carries its own algorithm and cost, so a file written today can be verified after both change. |
protobuf | none | The wire format: varints, zigzag, packed and nested fields. A message without its schema still reads, which is what makes a proxy possible. Not gRPC — that needs HTTP/2 and TLS. |
postgres | net | The v3 wire protocol and SCRAM-SHA-256, checked against RFC 7677's own vector. No TLS, so a trusted network or a local socket. |
xml | none | Parse and render. No DTD and no external entities, ever — that is what XXE is, and a first release does not need it. Which is also why this can declare nothing and mean it. |
oauth2 | none | The authorisation-code flow with PKCE (checked against RFC 7636's vector) and client credentials. PKCE and state are not optional here. |
563 of the 660 libraries declare
nothing. Only 97 ask for any capability
at all. That is the pattern the whole design is for, and the number is counted
from the manifests rather than asserted: reach is
split from computation, so a program that joins paths, formats a date or
builds a URL acquires no capability by doing so — and where a library really
does need the world, it asks for it as an effect the consumer supplies, which
is what log demonstrates.
They are three packages because http cannot open a
socket, and that is checked rather than claimed: its manifest declares no
capability, effects are inferred from its source, and a version of it that
started dialling out would fail to build in every consumer. So a program can
parse and route HTTP while remaining provably unable to reach the network, and
a program that only builds requests never acquires the ability to send them. In
every other language, depending on the HTTP library means depending on
something that can.
Where packages come from
The registry is called Blade. It is not a separate program —
grasm add pulls from it, grasm publish pushes to it,
and grasm deps resolves against it, all from the one binary.
Two sources work today: a path dependency, and a local Blade
registry under .grasm/registry (or wherever GRASM_REGISTRY
points). Both resolve, lock and check ceilings.