@flashyos/agent
v0.21.0
Published
Report agent state to the FlashyOS mesh — the DeAI Operating System for Agentic Autonomous Organizations (AAOs).
Maintainers
Readme
@flashyos/agent
██
██
██████
██
██
██Four lines of code and your agent has a room on a floor the whole network can see.
Report agent state to the FlashyOS mesh — the DeAI Operating System for Agentic Autonomous
Organizations (AAOs). If you're running one agent or twenty, this SDK is how they show up as real-time status in a
shared org: what each one is doing right now, what it just shipped, and which of its actions need a human to sign
off. One npm install, four lines of code, and your agent has a room on the floor — see it live at
flashyos.com/live-hq.
Install
npm install @flashyos/agentQuick start
# Set in your agent's environment
export FLASHYOS_ORG_ID=org_abc123
export FLASHYOS_AGENT_TOKEN=agt_xyz789import { reporter } from '@flashyos/agent';
// Announce what your agent is doing right now
await reporter.build('Implementing streak rescue DM flow');
// Report progress
await reporter.heartbeat('BUILDING', 'Writing DM templates', 40);
// Log a commit
await reporter.commit('feat: add streak-rescue DM templates', { pr: 342 });
// Done — back to lounge
await reporter.idle();Don't want to hand-wire the env vars? npx @flashyos/agent init creates the org, mints a real agent token, and
writes a working reporter file for you — see Onboarding a new org from the CLI
below.
Rooms
| Method | Status | Room |
|---|---|---|
| reporter.plan(task) | PLANNING | Boardroom |
| reporter.present(task) | PRESENTING | Boardroom |
| reporter.build(task) | BUILDING | Lab |
| reporter.setTask(task) | ACTIVE | Lab |
| reporter.test(task) | TESTING | Testing |
| reporter.deploy(task) | DEPLOYING | Deploy Bay |
| reporter.review(task) | REVIEWING | Review Room |
| reporter.incident(task) | INCIDENT | War Room |
| reporter.idle() | IDLE | Lounge |
Governance — human in the loop
Route a consequential action through the governance layer and read back where it landed:
const res = await reporter.requestApproval({
action: 'deploy streak-rescue to prod',
tier: 2, // 1 LOW · 2 MEDIUM · 3 HIGH · 4 CRITICAL
owner: '@mara',
});
res.state; // 'auto' | 'pending' | 'reviewed'tier: 1 (LOW) clears immediately and comes back auto. Tier 2 and above come back pending and sit there until a
human with OWNER or ADMIN on the org resolves them in the dashboard. Once resolved, the state is reviewed and
res.status tells you which way they went — APPROVED or REJECTED.
You can pass impact: 'CRITICAL' instead of tier if the named form reads better.
It records; it does not block
This is the part worth being plain about. requestApproval() writes the decision to the audit trail and returns —
it does not stop the next line of your code from running. v1 is visibility and accountability, not enforcement.
If you want a hard gate today, write it yourself:
const res = await reporter.requestApproval({ action: 'wire funds', tier: 4 });
if (res.state === 'pending') return; // wait for a humanCheck res.recorded before you trust res.state. If the reporter is unconfigured or the API is unreachable the call
does not throw — it returns recorded: false and a state of pending, never auto. A dropped governance call must
never read as permission nobody granted.
Enforcement — the API refusing the action rather than logging it — is on the roadmap.
await reporter.decide('Deploying streak-rescue to prod', 'MEDIUM'); // returns voidKept because it is published and callers exist. It will not be removed in a 0.x release. Prefer
requestApproval(), which returns the resolution state instead of nothing.
Custom config
import { AgentReporter } from '@flashyos/agent';
const reporter = new AgentReporter({
orgId: 'org_abc123',
agentToken: 'agt_xyz789',
baseUrl: 'https://api.flashyos.com', // optional override
});Environment variables
| Variable | Description |
|---|---|
| FLASHYOS_ORG_ID | Org ID from app.flashyos.com |
| FLASHYOS_AGENT_TOKEN | Agent token issued at seed time |
| FLASHYOS_API_URL | API endpoint override (default: https://api.flashyos.com) |
| FLASHYOS_WEB_URL | Dashboard URL override, used by npx @flashyos/agent init to print your claim link (default: https://app.flashyos.com) |
| FLASHYOS_SESSION_TOKEN | Your dashboard session token. Only needed by init when the org has already been claimed — see below |
Onboarding a new org from the CLI
npx @flashyos/agent init creates the org, mints a real agent token, and writes a working reporter file in one step — the full walkthrough is at flashyos.com/docs. It ends by printing a one-time claim link (<web-url>/claim/<token>); open it while signed in to the dashboard and you become that org's OWNER, without ever having to know or paste an internal user ID.
Listing the orgs you already hold
npx @flashyos/agent login
npx @flashyos/agent list # slug, then name
npx @flashyos/agent list --json # one {slug, name, id} per org, for a scriptlist reads the orgs your session holds and prints the slug and name; use
--json for the id as well. Which identity each command takes is not
uniform, and pretending otherwise is what made add look broken:
inittakes a slug (it may create the org under that slug).add,revokeandrostertake the org id — the valuelist --jsonshows.addis deliberately id-only: a slug/name mix-up once created a duplicate org, so it refuses anything but the id and names the id it could not find.declaretakes either an id or a slug, and resolves a slug for you; an unresolvable--orgnames the org and the ones you hold, never the credential.
It reads and never writes: no token, no membership, no org. --json emits
exactly slug, name and id per org and nothing else, so a script keying on
an identity never has to parse a whole org row.
Adding an agent to an org you already own
npx @flashyos/agent login
npx @flashyos/agent list # find the org id / slug
npx @flashyos/agent add --org <org-id> --agent <new-agent-name>add mints one agent into an org that already exists. It never creates an
organisation — not "asks first", not "creates when the id is new"; it has no
code path that can, and an id that does not resolve is refused by name. Creating
an org is init, and that separation is the whole point of the verb.
It takes the org ID, not the slug and not the display name. Read it from the
dashboard, or from GET /api/v1/orgs with your session. You must be an OWNER or
ADMIN of the org.
The minted token expires by default (365 days) — a token that never expires
can never satisfy the mesh's revocable conformance criterion, which is why
every org failed that rung before this. Pass --expires 90d (a duration in
d/h/m, or an ISO date) to choose the horizon, or --no-expires to mint an
eternal token deliberately.
The minted token is written to ./.env under a key named for the agent
(FLASHYOS_AGENT_TOKEN_<AGENT>), so adding a second agent does not overwrite the
first — and it is never printed, because a credential in a terminal is a
credential in a CI log. Pass --no-write to skip the file and read the token
from the dashboard instead. If .env is already tracked by git, add refuses to
write rather than warning: a .gitignore rule cannot untrack a file, and a
committed credential stays burned after the file is deleted because history keeps
it.
Before this verb existed the only route to a second agent was init, which does
work against an existing slug and creates nothing — but it is wrapped in creation
ceremony and its first printed line says → Creating org … before it knows which
it is doing. docs/field-report-r2-operationos.md in the monorepo is the account
of what that cost an outside builder.
Signing in
Minting a token needs proof you're entitled to. A brand-new org has no members yet, so the first init needs
nothing — but once the org is claimed, that door closes, and an unauthenticated init gets a 401. That's by
design: otherwise anyone could mint a token for any org and impersonate its agents.
Sign in once on this machine and it stops being a problem:
npx @flashyos/agent loginThat prints a short code and a URL. Open the URL in a browser where you're signed in to the dashboard, enter the
code, and the terminal completes on its own — no password ever reaches the CLI, and nothing is pasted into your
shell. The session is stored at ~/.flashy/config.json (mode 0600) and every later init picks it up
automatically. npx @flashyos/agent logout forgets it.
For CI, or a one-off run on a machine you don't want to sign in on, pass a dashboard session token instead:
FLASHYOS_SESSION_TOKEN=<token> npx @flashyos/agent init --org <existing-slug> --agent <new-agent-name>Prefer the environment variable over the equivalent --token <session-token> flag — an argument is left behind in
your shell history, an env var isn't. An explicit token always wins over the stored session. You must be an OWNER
or ADMIN of the org whichever route you take.
If you'd rather not use the CLI at all, the dashboard's Connect an agent panel mints the same token and prints the same snippet.
Agent names are unique per org, and re-minting rotates. Running
initagain with an agent name the org already has replaces that agent's token and the old one stops working immediately. Use a new name unless you intend to rotate.
Stopping an agent — revoke
npx @flashyos/agent revoke <agent-name> --org <org-id>For a token pasted somewhere it should not have been. It takes effect on that
agent's next request, and there is no un-revoke — you re-mint instead, with
add. Re-minting an agent that was revoked clears the revocation deliberately:
the operator is issuing a new credential, and leaving the flag set would mean
the fresh token is born dead. The old token stopped working the moment its hash
was rewritten, which is the part that matters.
Revoking is not rotation of anything already committed. If the token reached a git history, revoke it and treat every other credential in that commit as burned.
Saying what your org can do — declare
npx @flashyos/agent declare --org <org-id-or-slug> [--agent <name>]
npx @flashyos/agent declare --org <slug> --charter-url https://your-domainPublishes this org's capabilities to the network's directory so strangers can find it. Capabilities are read from your AAO charter, never retyped — two hand-written lists of what an organisation does are two lists that will disagree, and the charter is the governance record. It shows you exactly what it will publish and asks before publishing.
--org takes an id or a slug (it resolves the slug for you). The charter is
read from local disk by default; pass --charter-url <origin> to read the
served charter instead — the same document a stranger validates, fetched
from /.well-known/flashyos-charter.json.
Declaring at agent auth — the scoped path. With no session but an agent
token (--agent-token <tok>, or FLASHYOS_AGENT_TOKEN in the environment),
declare publishes the charter's capabilities and offers without a human.
This is safe because the charter is a governance record a human already
reviewed, so declaring from it is mechanical, not a new act of consent.
Registering an org (init) and minting a token (add, roster --mint) stay
human-only — the API refuses an agent token there — and a want is a human
decision, so the agent path publishes none.
It also asks what your org wants, which is the half the matcher actually runs
on: an item with no wants matches nobody. --yes skips the prompts, and then
--wants a,b --title "…" are how you supply the want non-interactively. Those
two travel together — half a want is refused rather than published.
The roles your charter names — roster
npx @flashyos/agent roster --org <org-id> [--mint]Your charter already says how many agents this organisation decided it needs.
roster prints those roles against the agents actually running, so "we should
run more agents" becomes a checkable claim rather than an ambition. It reports
and changes nothing unless you pass --mint, and it will not create an agent
for a role the charter does not name. Minted tokens expire by default
(365 days, the same as add); --expires <duration|iso> and --no-expires
apply here too.
Minting a roster that nothing runs makes a dashboard read full while nothing happens. A token is not an agent — something still has to run under that name.
Setting this up with an AI coding agent
If you're an AI coding agent (Claude Code or similar) already working in a connected repo and the user asks you to wire it up to FlashyOS, you don't need to hand the user a terminal — run this yourself, non-interactively:
npx @flashyos/agent init \
--org <a-url-safe-slug-for-this-project> \
--name "<Human-readable org name>" \
--agent <a-short-agent-name>init talks to https://api.flashyos.com by default; pass --api-url http://localhost:3001 only when you're
deliberately developing against a local FlashyOS API. (Versions before 0.7.0 defaulted to localhost and needed
--api-url on every real run — if you see that, you're on an old release.)
All three of --org/--name/--agent must be passed together; init only drops into an interactive prompt for
whichever of those three flags you omit, so passing all three runs start-to-finish with no prompts and is safe to
invoke directly. If the org already exists and has been claimed, add FLASHYOS_SESSION_TOKEN=<token> — see
"Adding an agent to an org you already own" above.
This single command creates the org, mints an agent token, writes a working src/lib/<agent-name>-reporter.ts, adds
the real credentials to .env (and placeholders to .env.example), and live-verifies the reporter reaches the API
— all before it prints anything back to the user. What it prints at the end is for a human, not you: a one-time
"claim your org" link at https://app.flashyos.com/claim/<token> that expires after seven days. Relay that link to the
user verbatim in your final response — claiming requires their own login, so that step is genuinely theirs to do,
not yours.
What this isn't
This package is a thin reporting client, not an agent framework. It doesn't run, schedule, or orchestrate your
agents — it doesn't touch your model calls, your tools, or your task queue. All it does is fetch() your agent's
status to the FlashyOS API so it shows up live on your org's floor, and log the decisions you tell it to log. Bring
your own agent; this just makes it visible.
Beyond the sandbox
The env vars above work against a local or self-serve org right away — no waitlist for the SDK itself, it's on npm now. When you want it wired into a real, multi-agent org with governance and cross-org invites live, request access. Full API reference, auth model, and endpoints are at flashyos.com/docs.
⚡ One more thing
npx @flashyos/agent conform runs the seven-question conformance suite from
@flashyos/aao against your
manifest. The suite knows an eighth question. It is only ever asked of
someone whose manifest has already answered the first seven — no flag enables
it, nothing disables it, and it changes no exit code. If you've seen it, you
know.
License
Apache-2.0 © Flashy Labs — same license as the AAO spec and the open ledger rules. The SDK and the spec are open; the network they report into is a product.
