CLI
The june command runs the workflow or chat a file default exports, and june doctor checks your setup. Bun imports .tsx and .ts files directly, so there's no build step, and a file's models, providers and stores are whatever its code builds: there are no provider or model flags.
| Need | Command |
|---|---|
| Run a workflow | june run review.tsx |
| Open an interactive conversation | june chat chat.ts |
| Ask once, or script a chat | june ask chat.ts "…" |
| Check Bun and provider keys | june doctor |
The CLI comes with the package as node_modules/.bin/june and requires Bun 1.2 or later. Run it as bunx june if it isn't on your PATH; Install covers setup.
june run
june run review.tsx
Renders the component the file default exports and runs it to completion. The Quickstart walks through a first run, and Running workflows covers what a run does. With options:
june run triage.tsx --input '{"repo":"johno/june","issues":[12,15]}'
june run triage.tsx --input-file ./triage.json
june run review.tsx --json > review.json
june run review.tsx --timeout 60000
- The file must default export a workflow component.
june: cannot find <file>if it doesn't exist, andjune: <file> must default export a workflow componentif its default export isn't a function. - Progress goes to stderr for each
<Step>,<FineTune>and<Evaluate>as it starts (▸ id), calls a tool (↳ tool {input}), streams text, and finishes (✓ id) or fails (✗ id: message). AuseStepor<Write>prints no progress, only its result. - Results go to stdout once every step has finished: each step's result under
── id, in the order the steps finished. A failed run prints no results, only the error on stderr. - Tools. The CLI doesn't add tools to a workflow: it runs the tools the workflow's own
<Agent>declares, including<Bash />. - Approvals. When a step asks to run a tool that needs approval,
june runasks on stderr,? Allow <tool> {input} (step <id>)? [y/N], and reads the answer from stdin.yoryesapproves; anything else, or the end of stdin, denies.
Options
--input <json>passes a JSON object to the component as its props, asrun(<Workflow {...input} />)would. It must be an object:june: --input must be a JSON object of the workflow's propsfor anything else, andjune: --input is not valid JSONwhen it doesn't parse. June never prints the input itself, even in errors; input your workflow puts in a prompt or a result shows up wherever those do, including--json'stree.--input-file <path>reads the props from a JSON file, relative to the current directory. Use one of--inputand--input-file, not both. Without either, the props are{}.--jsonprints the whole result to stdout as one JSON object once the run succeeds (a failed run prints nothing to stdout):steps(each result, by step id),usage(the tokens the run used, when steps reported any) andtree(the run's trace). Progress stays on stderr, so stdout parses. Use it for anything that reads the output: the plain text format may change, the JSON follows the compatibility rules.--timeout <ms>aborts the run after that many milliseconds, a positive number. A run that times out fails withjune: The operation timed out.
Exit status
0when every step finished.1when a step failed, the run timed out, or the file or options were wrong. The message is on stderr, afterjune:.130when you pressed Ctrl-C. The first Ctrl-C aborts the run; a second exits at once.
june chat
june chat chat.ts
An interactive chat in your terminal with the chat a file default exports, such as one made with createChat() from june/chat. Chat covers what a chat is and how sessions work.
import { openai } from "june/sdk/openai";
import { createChat, fileStore } from "june/chat";
export default createChat({
model: openai("gpt-5-mini"),
instructions: "You are helping build June.",
store: fileStore(".june/chat"),
});
$ june chat chat.ts
session 4f9c…e1
/new starts a session, /session prints its id, /feedback up|down rates the last reply, /quit exits
> What is June?
June is a declarative runtime for AI workflows…
> Say that in five words.
Declarative AI workflows, in React.
>
A chat in the terminal's normal scrollback, not a full-screen app. Replies stream to stdout; the > prompt, the session id and status go to stderr. A blank line separates turns.
--session <id>reopens a saved session:june chat chat.ts --session <id>. It needs a persistent store, such asfileStore(".june/chat"). With the defaultmemoryStore(), a session ends with its process, and--sessionfails withno chat session.- Commands.
/newstarts a new session,/sessionprints the current id,/feedback upor/feedback downrates the last reply, and/quitor Ctrl-D exits. - Ctrl-C while a reply streams cancels that turn (it's recorded as canceled and left out of later context) and returns to the prompt. Ctrl-C at the prompt exits with status 130.
- Errors. A failed turn prints its error and returns to the prompt.
- Approvals. When a workflow chat's step asks to run a tool that needs approval, it asks on stderr, like
june run:yapproves, anything else denies.
Sessions and stores covers what a session stores and how it reopens.
june ask
june ask chat.ts "Explain this package"
One turn with the same chat, for scripts. The prompt is the remaining arguments, or stdin when there are none:
june ask chat.ts --session <id> "And its tests?"
git diff | june ask chat.ts
june ask chat.ts --json "Explain this package" > reply.json
june ask chat.ts -- "-h means help?"
The reply streams to stdout, followed by a newline, and session <id> goes to stderr, so --session can continue the conversation later. With --json, the id is the object's sessionId instead.
--session <id>continues a saved session.--jsonprints exactly one JSON object to stdout once the turn completes, and nothing else.--ends the options, so a prompt can start with-.- Approvals are asked on stderr and answered on stdin, so a prompt piped on stdin leaves nothing to answer with and the call is denied.
{
"sessionId": "4f9c…e1",
"turnId": "b2d1…07",
"text": "June is a declarative runtime for AI workflows…",
"metadata": {
"responder": { "kind": "model" },
"model": { "provider": "openai.responses", "modelId": "gpt-5-mini" },
"usage": { "inputTokens": 24, "outputTokens": 31, "totalTokens": 55 },
"finishReason": "stop"
}
}
metadata is the turn's provenance. A failed turn exits 1 with the error on stderr, and Ctrl-C cancels it and exits 130.
june doctor
june doctor
june doctor review.tsx
Checks that Bun is 1.2 or later and which provider API keys are set, without calling a model.
- With a file, it finds the providers the file and its local imports use: each
june/sdk/<provider>or@ai-sdk/<provider>import, and a gateway model string such as"anthropic/claude-sonnet-5-5". It reports the key each needs and exits 1 if one is missing. - Without a file, it lists every key it knows and exits 1 only if none is set.
| Provider | Key |
|---|---|
@ai-sdk/openai | OPENAI_API_KEY |
@ai-sdk/anthropic | ANTHROPIC_API_KEY |
@ai-sdk/google | GOOGLE_GENERATIVE_AI_API_KEY |
@ai-sdk/groq | GROQ_API_KEY |
@ai-sdk/mistral | MISTRAL_API_KEY |
@ai-sdk/xai | XAI_API_KEY |
| AI Gateway | AI_GATEWAY_API_KEY |
It doesn't check that a key is valid, or that the model a file names exists. Those show up when you run.
Help and version
--help,-h,june helporjunealone prints the usage, options and examples.--version,-vprints the installed version.- An unknown command exits 1 with
june: unknown command <name>, run 'june --help' for usage.