Skip to content

Starting the app

See Installing if you haven't installed Janissary yet.

Run

> janus

from the project directory.

janus starts the server in the background and hands your shell prompt straight back once it's ready. The terminal you launched from doesn't need to stay open, and closing it — or pressing Ctrl+C in it — no longer stops the app. Use janus stop to shut it down.

By default each launch starts fresh: a single janus tab, with any state from the previous session cleared. To pick up where you left off instead, use --relaunch (below).

Arguments

ArgumentWhat it does
<project-dir>Target directory to work against (default: current directory).

Flags

FlagWhat it does
--port=<n>Listen on port n (1–65535). Without it, a free port is picked automatically.
--no-openStart the server without opening the app window; prints the server URL to the terminal instead.
--relaunchRestore the previous session instead of starting fresh.
--helpPrint usage and exit.
--versionPrint the name and version and exit.

A mistyped flag, a bare --port with no value, or a port outside 1–65535 stops the launch with an error and a pointer to --help — nothing is started and no state is touched.

Stopping the app

Since a normal launch detaches into the background, closing the terminal doesn't stop it. Run this from the project directory instead:

> janus stop

It shuts down the instance running against the current directory. Pass a directory to stop an instance running elsewhere:

> janus stop <project-dir>

janus stop runs attached and prints straight to the terminal. It signals the running server to shut down gracefully, closing every open browser window before it exits. If nothing is running there, it prints no running janus instance for <dir> and exits without error — there being nothing to stop isn't a failure.

Closing the app window stops it too. When the last window or browser tab showing the app goes away, the server waits one second and then shuts down, the same as janus stop. The pause is there so a page reload or a browser back-and-forward can reconnect without losing your session; if a window comes back within that second, the shutdown is cancelled. If you have the app open in two windows, closing one changes nothing.

Resuming a session with --relaunch

janus --relaunch

--relaunch rebuilds your tabs as you left them: every agent tab comes back in its saved order with its dot color, group, transcript, command history, and working directory. Tab aliases and scheduled commands are restored too. What doesn't come back: view tabs (images, Markdown, editors, web pages), harness tabs, and workspace clones — those are live views and processes, not saved state.

Troubleshooting

Since a normal launch doesn't print to the terminal, check .janissary/log/server.log for anything the server would otherwise have shown — it's cleared at the start of each normal launch and kept (with new output appended) across --relaunch.

If saving an agent's relaunch state fails, Janissary keeps the last valid state file and writes one warning for that agent to the server log. It suppresses repeated warnings while the same failure continues, then reports again if persistence recovers and later fails anew.

If startup fails, the error names the app and version, says what went wrong, and suggests what to do next. The ones you're most likely to see:

  • The port is already in use — something else is listening on the port you asked for. Pick another with --port=<n>, or drop --port entirely and let the app choose a free one.
  • Another instance is already running here — a second janus launched against the same directory as a still-running instance is rejected with the live process's ID. Run janus <dir> to start a second instance against a different directory.
  • Permission denied binding to the port — ports below 1024 need elevated privileges. Pick one above 1024 with --port=<n>.
  • The web UI bundle is missing — you're running from a source checkout whose web assets were never built. Run npm run build:web, or npm start, which builds first.

If the server never reports itself ready within 20 seconds, the launcher stops waiting, kills it, and tells you it timed out.

For a failure you can't place from the message alone, set JANUS_DEBUG=1 and launch again. The full stack trace is printed after the message, in the terminal and in the log:

JANUS_DEBUG=1 janus

Configuration

Settings live in .janissary/config.json inside the directory you launch from; a default file is created on first launch. Every setting is editable in the file:

SettingDefaultWhat it does
transcriptMaxLines25000How many transcript entries each tab keeps. Past the cap, the oldest entries are dropped.
tabNameMaxLength16The longest inactive tab name shown in the strip. Longer names end in . This also limits new agent and harness names.
activeTabNameMaxLength50The longest focused tab name shown in the strip. Focusing a tab expands its name up to this limit.
theme"dark"The application color theme. Change it at runtime with theme <name>.
syntaxTheme"github-dark"The syntax-highlighting theme for editor tabs. Change it at runtime with syntax theme <name>.
sandboxWorkspacestrueWhether workspaced tabs are confined to their workspace clone by the macOS sandbox. See Workspacing.
notificationsall events offWhich background events feed the notifications tab. There's no runtime command for this; edit the file directly.
syncPaths["product/backlog/", "product/plans/"]Project-relative paths kept synced with GitHub in the editor. See Git-synced files for the entry syntax and how a sync happens. There's no runtime command for this; edit the file directly.
externalViewers{ "video": "QuickTime Player" }Which application each viewer hands a file to on open external, keyed by the viewer's name — video and audio today. Give it a macOS application name; an empty or missing entry uses your operating system's own default. A map you set replaces the default outright rather than merging with it. There's no runtime command for this; edit the file directly.

Changing theme or syntaxTheme at runtime atomically rewrites this file, preserving every other key, and applies the running change only when that write succeeds. If the file isn't valid JSON, the app warns on startup and falls back to defaults for that session — your file is left untouched so you can fix it. Within valid JSON, a setting with the wrong type falls back independently to its default, as do missing notification event toggles.