Skip to content

Repository files navigation

Station screenshot

macOS Node Licence Works with


Station

A station for your AI agents.

A station is a fixed point that things return to. Somewhere you hold your position, stay informed, and decide what happens next. In a world where agents go out and do the work, Station is where they come back to report in.

Running scheduled agents can feel like you're working without any real visibility. Did it run? Did it find anything useful? Did something go wrong at 3am and it just sat there? You end up opening log files or checking outputs one by one, which defeats the purpose entirely. Station keeps all of it in one place, giving you a visual inbox of agent updates, with separate tabs for work and personal so nothing bleeds into the wrong part of your day.

When an agent finishes a task it drops a small update into a local folder. Station picks it up, showing you what it did, what files it created, and whether it needs anything from you before the next run.

It works with any AI agent that can write a file, whether that's Claude, ChatGPT, a custom script, or anything else. When something needs following up, the Discuss button copies a pre-filled message to your clipboard so you can paste it straight into whichever AI tool you use and pick up where the agent left off.

Station runs on your machine, just a local folder your agents write to and a small app that reads it.


Install

Requirements: macOS · Node.js 18+

git clone https://github.com/catrinmdonnelly/station.git
cd station
npm install
npm start

Station opens in widget mode on first launch and creates a config file at ~/.station/config.json. Right-click anywhere in the widget to switch to app or menu bar mode. You can also cycle through four built-in themes (Station red, light, dark, and glass) using the theme button at the top of the widget.

On first launch Station leaves a single welcome card in the inbox so you can see it working before you have any agents posting. Tick it off once you have read it and it will not come back.

Run without a terminal (recommended)

To have Station start automatically at login and run in the background without keeping a terminal window open:

bash setup.sh

This creates ~/Applications/Station.app and adds it as a macOS Login Item. You can close the terminal straight after and Station will be there every time you log in.

Custom inbox path:

bash setup.sh /path/to/your/inbox

What you see

Each agent entry shows up as a card with one of four statuses:

Status What it means
error Something failed and needs your attention (sorts to top, shown in red)
needs_input The agent is blocked and waiting on you
fyi Work done, nothing urgent
completed All finished, ready to dismiss
responded You answered a card's buttons, set by Station rather than by an agent

You can tick items off, snooze them until 8am tomorrow, open the full brief the agent wrote, or copy a pre-filled message to pick up the conversation in your AI tool. Station refreshes automatically and shows a live badge count in the dock for anything urgent.

Tabs

Station starts with Work and Personal, but the tabs are yours to change. Click the + at the end of the tab strip to add one, and double-click any tab to rename it. Clearing the name deletes the tab. Plenty of people run a tab per project rather than the default two.

A tab's name becomes the category your agents write: a tab called "Client Work" is "category": "client-work". Renaming a tab updates the cards already in it, and deleting a tab moves its cards to the first tab rather than losing them. A card whose category matches no tab shows up in the first tab, so nothing an agent sends can vanish.

Keeping the widget on top

Right-click the widget and tick "Keep on top" to pin it above your other windows, including full screen apps. The choice is remembered.


Claude Code plugin

If you use Claude Code or Cowork, there's a plugin included in the plugin/ folder that lets your agents post to Station directly without having to write the JSON themselves. Drop the plugin folder into your Claude plugins directory and it handles the rest.


How agents post to Station

At the end of a run, your agent writes a JSON file to the inbox folder:

{
  "agent": "seo-monitor",
  "agent_display": "SEO Monitor",
  "timestamp": "2026-04-08T09:00:00",
  "status": "needs_input",
  "category": "work",
  "headline": "Three pages dropped out of top 10, manual review needed",
  "summary": "Pages /products, /about, and /contact lost ranking overnight. Likely a crawl issue. Checked sitemap, all present. Needs eyes before next scheduled run.",
  "actions_needed": [
    "Check Google Search Console for crawl errors",
    "Confirm sitemap is being picked up correctly"
  ],
  "files_created": [
    "outputs/seo-report-2026-04-08.md"
  ],
  "full_brief_path": "outputs/seo-brief-2026-04-08.md"
}

File naming: [agent-name]-[YYYY-MM-DD-HHMM].json

Getting the most out of it

Station becomes genuinely useful when your agents are well identified. A few things that make a real difference in practice:

agent_display is what shows on the card, so give it a proper human-readable name rather than leaving it as the machine name. "SEO Monitor" or "Weekly Brief" reads much better than "seo-monitor-v2".

headline is the one line you'll read when you're scanning Station quickly, so make it specific enough to tell you whether you actually need to do something. "Run complete" tells you nothing. "Three pages dropped out of top 10, manual review needed" tells you exactly what you're dealing with.

summary is where the agent should give you enough context to act without having to open the full brief. Think of it as the agent explaining itself to you in a couple of sentences.

category routes entries to the right tab, so if you're running both work and personal agents, make sure each one sets this correctly. Anything without a category defaults to the Work tab.

The more clearly your agents identify themselves and describe what they did, the more Station feels like a proper briefing rather than a list of log entries.

Status values

Status When to use
error Agent crashed or couldn't complete the run
needs_input Agent is blocked and needs you to do something
fyi Work done, no action needed
completed Everything finished, nothing blocking
responded Set by Station when you answer an interactive card. Agents do not write this

Category values

Whatever your tabs are called, lowercased with spaces turned into hyphens:

Category Tab
work Work tab (default if omitted, and where unrecognised categories land)
personal Personal tab
client-work A tab you added called "Client Work"

Bash snippet

TIMESTAMP=$(date +%Y-%m-%dT%H:%M:%S)
INBOX="$HOME/.station/inbox"
cat > "$INBOX/my-agent-$(date +%Y-%m-%d-%H%M).json" << EOF
{
  "agent": "my-agent",
  "agent_display": "My Agent",
  "timestamp": "$TIMESTAMP",
  "status": "fyi",
  "category": "work",
  "headline": "Weekly report ready, 3 items flagged for review",
  "summary": "Run completed successfully. Found 3 items that need attention before next scheduled run.",
  "actions_needed": [],
  "files_created": []
}
EOF

Posting over HTTP instead of writing files

Writing a JSON file is the simplest way in, but Station also accepts cards over HTTP while it is running. Useful for agents that cannot easily write to your disk, or that already speak HTTP.

curl -X POST http://localhost:2626/api/cards \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "deploy-bot",
    "headline": "Build 214 is ready to ship",
    "summary": "All tests green.",
    "status": "needs_input",
    "category": "work"
  }'

Only agent and headline are required. Everything else falls back to the same defaults as a file-based card. The response gives you back the card's ids:

{ "ok": true, "entry_id": "deploy-bot-2026-08-24-185146", "card_id": "deploy-bot-2026-08-24-185146" }

Cards you can answer

A card can carry buttons, so instead of reading an update you answer it and the agent picks up your decision. Add an interactive block:

{
  "agent": "invoice-agent",
  "headline": "Send the March invoice?",
  "summary": "Drafted and ready. Needs your say-so before it goes.",
  "interactive": {
    "card_id": "inv-march",
    "components": [
      { "type": "approval", "approve_label": "Send it", "decline_label": "Hold" }
    ]
  }
}

Two component types:

Type What it gives you
approval Two buttons. Labels default to Approve and Decline
buttons Your own set, from an options list of { value, label, style } where style is primary, secondary or destructive

When you press a button, Station writes your answer to responses/<card_id>.json inside the inbox folder and flips the card to responded:

{
  "card_id": "inv-march",
  "responded_at": "2026-08-24T17:52:09.895Z",
  "values": { "approval": "approve" }
}

Your agent watches for that file to know what you decided. If the card includes interactive.callback_url, Station POSTs the same payload straight to it instead of making you poll.

Set accent on a card to colour its buttons, so an agent's cards are recognisable at a glance.

If you would rather not hand-roll the sending and the waiting, helpers/ has a small zero-dependency library for Python and one for Node that does both. See helpers/README.md.


Slack-shaped payloads

If you already have an agent that builds Slack Block Kit messages, point it at the Slack adapter and Station will translate the blocks into a card, buttons included, with no changes to the agent:

curl -X POST http://localhost:2626/api/adapters/slack \
  -H "Content-Type: application/json" \
  -d '{"agent":"ci","blocks":[
        {"type":"header","text":{"text":"Deploy failed on main"}},
        {"type":"section","text":{"text":"Step 4 timed out."}},
        {"type":"actions","elements":[
          {"type":"button","text":{"text":"Retry"},"value":"retry","style":"primary"}]}]}'

header and section blocks become the headline and summary, and actions become buttons you can press.


Configuration

Config lives at ~/.station/config.json:

{
  "inbox": "~/.station/inbox",
  "workspace": "~/.station",
  "port": 2626,
  "tabs": ["Work", "Personal"],
  "mode": "widget"
}
Key Default Description
inbox ~/.station/inbox Folder Station watches for JSON entries
workspace the folder holding inbox Base that relative full_brief_path values resolve against
port 2626 Local port for the HTTP server
tabs ["Work", "Personal"] Tab labels (maps to category in your JSON files). Editable from the tab strip
mode widget widget, app, or menubar
pinned false Keep the window above everything else
width 320 Widget width in pixels (saved automatically on resize)
height 600 Widget height in pixels
x / y — Widget position (saved automatically on drag)

How it works

Station is a Node.js HTTP server that reads JSON files from your inbox folder and renders them as HTML. In Electron mode, main.js wraps the server in a native window with a live dock badge and system notifications, watching the inbox folder with fs.watch() so updates appear immediately. setup.sh creates a native macOS app wrapper and Login Item so the whole thing starts on login without a terminal.

Agents write files in, Station reads them out. Dismissed items move to archived/, snoozed items move to snoozed/ and return the next morning, and answers to interactive cards land in responses/. Renaming or deleting a tab rewrites the category on the cards it held, so a tab change never strands a card.

Everything lives in plain files you can read, move or delete yourself. There is no database and nothing leaves your machine.


Uninstall

Delete the station folder. If you ran setup.sh, also remove the app and login item:

rm -rf ~/Applications/Station.app
rm -rf ~/.station

Then go to System Settings → General → Login Items and remove Station if it's still listed. Your inbox folder is left untouched.


Built by

I'm Catrin, a solo founder who's building with AI and wanted to share this along the way. Station is something I use every day to keep across what my agents are up to, and it felt worth putting out in case it's useful for you too. This is my first open source project, so any problems please let me know @catrinMdonnelly.


Licence

MIT

About

A station for your AI agents

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages