tokens: claude: 2187 o200k: 1571 api: 3pm-backend 0.64.0 about: "how to put an application on this fleet: an SDK inside the app, the app started by 3pm, the host linked to a bucket. Its metrics, events and actions then reach this backend through the host's agent, with no route of yours in between; the routes under `read` give them back" catalog: "https://3pm.edgecr4ft.net/sdk/sdk.json — every SDK version, file and sha256" docs: "https://3pm.edgecr4ft.net/llms.txt — the SDK page of each language, in full" steps[3]: 1. install 3pm on the host: curl -fsSL https://3pm.edgecr4ft.net/install.sh | sh 2. link the host to a bucket: run the paste line of `bucketToken` (or of `createToken`) there; with the bucket's `approval` on, `approveNode` admits it 3. start the app under 3pm (`3pm start app.js --name api`, or an ecosystem file): outside 3pm (no THREEPM_CTL_SOCK in its environment) every SDK call is a no-op, and nothing raises sdks[4]{id,package,version,install,metrics,events,actions,call,streams}: node,@3pm/api,0.64.0,"npm i https://3pm.edgecr4ft.net/sdk/node/3pm-api-0.64.0.tgz",yes,yes,yes,yes,yes python,threepm-io,0.64.0,"pip install --index-url https://3pm.edgecr4ft.net/simple/ threepm-io",yes,yes,yes,yes,no rust,threepm-io,0.64.0,"cargo add threepm-io --registry threepm, after declaring the registry in .cargo/config.toml: [registries.threepm] index = \"sparse+https://3pm.edgecr4ft.net/sdk/cargo/\"",yes,yes,yes,no,yes cpp,threepm_io,0.64.0,"FetchContent_Declare(threepm_io URL https://3pm.edgecr4ft.net/sdk/cpp/threepm-io-cpp-0.64.0.tar.gz URL_HASH SHA256=), FetchContent_MakeAvailable(threepm_io), target_link_libraries( PRIVATE threepm::io)",yes,yes,no,no,no node: const { io } = require('@3pm/api'); io.init({ source: 'worker', builtins: true }); const requests = io.counter('http.requests', { labels: { method: 'GET' } }); const latency = io.histogram('http.latency', { unit: 'ms' }); io.metric('queue.depth', () => queue.length); requests.inc(); latency.observe(12.5); io.event('deploy', { level: 'warn', attrs: { version: '1.2' } }); io.notifyError(err); io.action('cache.flush', { timeout_ms: 5000 }, async (params) => ({ flushed: params.prefix })); python: import threepm_io as io io.init(source="worker") requests = io.counter("http.requests"); latency = io.histogram("http.latency", unit="ms") io.metric("queue.depth", lambda: len(queue)) requests.inc(); latency.observe(12.5) io.event("deploy", level="warn", attrs={"version": "1.2"}) io.notify_error(err) @io.action("cache.flush", timeout_ms=5000) def flush(params, ctx): return {"flushed": params.get("prefix")} rust: use threepm_io::serde_json::{json, Value}; use threepm_io::{io, Action, ActionCtx, Event, Init, Level, Metric}; io().init(Init::new().source("worker")); let requests = io().counter("http.requests", Metric::new()); let latency = io().histogram("http.latency", Metric::new().unit("ms")); requests.inc(1.0); latency.observe(12.5); io().event("deploy", Event::new().level(Level::Warn).attr("version", "1.2")); io().action("cache.flush", Action::new().timeout_ms(5_000), |p: Value, _: &ActionCtx| -> Result { Ok(json!({ "flushed": p["prefix"] })) }); cpp: #include using namespace threepm::io; Io& io = instance(); InitOptions o; o.source = "worker"; io.init(o); auto requests = io.counter("http.requests"); auto latency = io.histogram("http.latency", [] { HistogramOptions h; h.unit = "ms"; return h; }()); requests.inc(); latency.observe(0.42); EventOptions ev; ev.level = "warn"; ev.attrs.add("version", "1.2"); io.event("deploy", ev); read: what the app sent, from this API (auth=user, under the bucket its host linked to; GET /api/v1/routes?route= for each in full) nodeAppMetrics the last values of every instance, live: sources, series, histogram buckets, declared actions metricsInventory what is stored: an app metric `http.latency` is the metric `app.http.latency`, and `apps` names the apps that emit it queryMetrics its history: {"range": {"from": "now-1h"}, "queries": [{"ref": "A", "metric": "app.http.latency", "filters": [{"label": "app", "op": "eq", "value": "api"}]}]} eventsQuery `io.event` / `notifyError`: filters `kind: app`, `app`, `event_name`, `level` nodeActions the actions the apps declared; `nodeAction` runs one, `getCall` reads its outcome setNodeAccess `fleet:invoke` on a node lets its apps `io.call` / `io.open` the apps of other nodes rules: - a metric name is dotted (`http.latency`) and stored as `threepm_app_http_latency`: `a.b` and `a_b` are one series - gauges, counters and histograms are stored; a meter is live only (`nodeAppMetrics`), never in `queryMetrics` - a gauge whose name ends in `total`, `count`, `sum` or `bucket` (after `_` or `.`) is dropped by this backend: it would collide with a counter's or a histogram's series - past 50 label sets a metric folds into one `overflow="true"` series; create a handle once and keep it, never derive `.labels()` per sample - one `source` per connection (`main` by default for the process 3pm spawned); a connection without a source of its own declares no action - the full reference, the bounds and every call: the SDK page of the language, listed in `docs`