# \[ANN\] julia-client — persistent Julia sessions as CLI

**URL:** <https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330>\
**Category:** Package Announcements\
**Tags:** ai\
**Created:** [May 29, 2026, 1:12am UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330 "2026-05-29T01:12:31Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [May 29, 2026, 1:12am UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/1 "2026-05-29T01:12:31Z")

</div>

Julia’s startup + compilation tax is brutal when an AI assistant (or a shell loop, or CI) spawns a fresh `julia` on every call. Inspired by [julia-mcp](https://github.com/aplavin/julia-mcp), [julia-client](https://github.com/Beforerr/julia-client) solves the same problem, but as an ordinary command-line tool — one static binary, usable by humans, scripts, and _any_ agent.

## What it is

A single Go binary that is both client and daemon. First `eval` auto-starts a background daemon over a Unix socket; it holds long-lived `julia -i --project=<dir>` processes so variables, loaded packages, and session state survive between calls. Idle daemon shuts itself down after 1h.

```bash
curl -fsSL https://raw.githubusercontent.com/Beforerr/julia-client/main/install.sh | bash

julia-client --project=@temp -e 'using Pkg; Pkg.add("DataFrames"); using DataFrames' # daemon starts; pkg loaded
julia-client --project=@temp -E 'df = DataFrame(a=1:3)' # -E displays the result
julia-client --project=@temp -e 'sum(df.a)' # state persists, no restart

```

## Features

- **Feels like normal Julia.** We mimic `julia` CLI: `-e` / `-E`, `--project` with the usual selectors (`@.`, `@temp`, named shared envs), running a file directly (`julia-client script.jl`), and stdin piping. If you know `julia`, you already know this.
- **Just a CLI.** No MCP, no client config, no JSON wiring. Works in a terminal, a bash script, or an agent. Project env auto-detected by walking `$PWD` for `Project.toml`.
- **Single binary, zero runtime deps.** Pure Go. `curl | bash` and go.
- **Live streaming output.** stdout and stderr come back as separate NDJSON frames _as they happen_, captured at the OS-pipe level — not buffered until the call ends.
- **Robust errors via a dedicated control channel.** Errors are read off a separate fd-3 frame, never scraped from stdout. Tiered tracebacks: `--trace short|smart|full` (`smart` hides Julia/client internals, keeps your frames). Replay the last traceback without rerunning: `julia-client trace`.
- **Real interruption.** `julia-client interrupt` sends SIGINT (then SIGKILL after 3s). Killing the client also interrupts the in-flight eval — so `timeout 30 julia-client -e 'might_hang()'` just works, no orphaned runaway computation.
- **Flexible session routing.** Key by project path (default, `--project=@.`), by env selector (`@temp`, `@shared`), or by a named `--session LABEL`. `--fresh` resets a session.
- **Revise auto-reload** for edited package code; `--fresh` for the cases Revise can’t track (struct redefs, new module deps).

## Built for agents: the skill

An [Agent skill](https://github.com/Beforerr/julia-client/blob/main/skills/julia-client/SKILL.md) ships in the repo, so assistants drive `julia-client` exactly the way you do — same flags, same sessions, no MCP server to stand up.

```bash
npx skills add https://github.com/Beforerr/julia-client

```

## Links

- Repo: [GitHub - Beforerr/julia-client: Persistent Julia REPL client and daemon · GitHub](https://github.com/Beforerr/julia-client)
- Alternatives: [julia-mcp](https://github.com/aplavin/julia-mcp), [DaemonicCabal.jl](https://github.com/tecosaur/DaemonicCabal.jl) (Linux-only)

Feedback welcome.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 29, 2026, 2:09am UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/2 "2026-05-29T02:09:13Z")

</div>

Could you clarify how sessions are launched and reused, and relative to the `--project` flag?

> [@Beforerr](#):
>
> **Flexible session routing.** Key by project path (default, `--project=@.`), by env selector (`@temp`, `@shared`), or by a named `--session LABEL`.

This reads like specifying different projects will launch new Julia sessions, which makes sense to avoid some unseen dependency incompatibilities. However, the README has this:

```julia-auto
# Explicit project environment
julia-client --project /path/to/project -e 'using MyPackage'
julia-client --project @temp -e 'using Pkg; Pkg.add("Example")'
julia-client --project @shareAnyname -e 'using Example'

```

which seems to suggest different lines of the same “script” is being run in one session activating different projects, in sharp contrast to the example here:

> [@Beforerr](#):
>
> ```julia-auto
> julia-client --project=@temp -e 'using Pkg; Pkg.add("DataFrames"); using DataFrames' # daemon starts; pkg loaded
> julia-client --project=@temp -E 'df = DataFrame(a=1:3)' # -E displays the result
> julia-client --project=@temp -e 'sum(df.a)' # state persists, no restart
> 
> ```

---

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [May 29, 2026, 2:31am UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/3 "2026-05-29T02:31:31Z")

</div>

A session’s project is fixed at launch. Passing a different `--project` does **not** re-activate the project of a running session — it routes to (and, if needed, starts) a _different_ session. So different `--project` values are different processes with independent state, while the same key always reuses the same process. Use `--session LABEL` when you want one session reachable from multiple directories.

---

<div class="post-metadata">

**Author:** ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)\
**Post date:** [May 29, 2026, 8:05am UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/4 "2026-05-29T08:05:36Z")

</div>

This has been around for many years and predates the LLM era:

> **[GitHub - dmolina/DaemonMode.jl: Client-Daemon workflow to run faster scripts in...](https://github.com/dmolina/DaemonMode.jl)**
>
> Client-Daemon workflow to run faster scripts in Julia

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [May 29, 2026, 1:16pm UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/5 "2026-05-29T13:16:18Z")

</div>

When (in which scenarios) to use DaemonMode and when to use julia-client ?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 29, 2026, 1:35pm UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/6 "2026-05-29T13:35:53Z")

</div>

Nice to see this space explored! There are definitely pros/cons to both the [julia-mcp](https://discourse.julialang.org/t/ann-julia-mcp-persistent-julia-sessions-for-ai-assistants/135386) and this kind of standalone CLI tool approach. The main tradeoff is:

- MCP: **(+)** no lifecycle/lingering daemons to manage, julia sessions are scoped to AI sessions, naturally handles multiple independent sessions per julia env, works on all OS; **(-)** AI-specific, infeasible to use from outside.
- standalone CLI: **(+)** benefits all of AI / users / scripts equally, can be used anywhere; **(-)** necessary to have long-running background processes, need special plumbing to get multiple independent julia sessions for the same folder.

I don’t know if it’s possible to somehow get best of both worlds… 🙂

// also cc @tecosaur who worked on something similar recently

---

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [May 29, 2026, 1:39pm UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/7 "2026-05-29T13:39:48Z")

</div>

Here is a short summary from Claude

```julia-auto
DaemonMode does cover the core value prop — warm process, persistent snippet state via runexpr, live output streaming. Confirmed by running it.

Where it genuinely differs (all verified, not inferred):
- No stream separation — stdout and stderr are merged.
- No structured/leveled errors — raw stacktrace only, no smart filtering or trace replay.
- No session isolation — single shared Main; concurrent clients can clobber each other's globals.
- No interrupt and no disconnect-cleanup — a killed/timed-out client leaves its computation running server-side to completion.
- No auto result display, no per-session threads.

So the earlier "when to use which" holds, now grounded:

- DaemonMode — fine when you want one warm shared scope and either fast stateless script runs (runargs) or simple persistent snippets (runexpr), and you don't care about isolation, interruptibility, or machine-parseable output. Pure-Julia, cross-platform.
- julia-client — the things it adds over DaemonMode are exactly the things it tests and DaemonMode lacks: keyed/isolated sessions, separated stdout/stderr/error channels, leveled tracebacks, real interrupt + client-disconnect cleanup, and a dependency-free (Go) client. That's what makes it the better tooling/agent backend.

```

Personally I found it quite usefully when you can use `julia-client --project=test ...`, `julia-client --project=benchmark ...` and running experiment like `julia-client --session=exp1 ...`. It tries to mimic `julia` command line, so AI is pretty efficient to combine with `grep`, `timeout` and all other command line utilities.

---

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [May 29, 2026, 2:12pm UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/8 "2026-05-29T14:12:55Z")

</div>

Thanks and very much inspired by you.

For multiple concurrent AI sessions I usually give each its own git worktree anyway, and since julia-client keys sessions by project path, separate worktrees get independent Julia sessions automatically, no extra plumbing.  
What I really like about cli-based skill is that it is very tunable and cost 0 tokens until invoked. Skill lets each user/team/project re-tune the agent’s behavior to have different default routing, project-specific setup snippets by simply editing markdown.

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [June 5, 2026, 12:22pm UTC](https://discourse.julialang.org/t/ann-julia-client-persistent-julia-sessions-as-cli/137330/10 "2026-06-05T12:22:56Z")

</div>

It seems to have been renamed to [repld](https://github.com/Beforerr/repld).
