Skip to content

vlune/selena

selena-social

CI License: Apache-2.0

Selena

Build a real agent in one JSON file. Tools, memory, sub-agents, and behavior — all declared, no code to write or compile.

Selena is a local-first agentic runtime. You describe an agent in agent.json, point it at a model you already run with Ollama or llama.cpp, and Selena drives the loop: the model calls tools, reads the results, and keeps going until the task is done.

No cloud. No API key. No data leaves your machine — the only network traffic is between Selena and your local model server.

// agent.json — this is the whole agent
{
  "name": "code-helper",
  "provider": "ollama",
  "model": "qwen3.5:2b",
  "system_prompt": "You are a terse coding assistant.",
  "tools": ["bash", "read_file", "grep"]
}
› find all TODO comments in the codebase and summarise them
  ⋯ bash
  ✓ bash
Found 14 TODOs across 6 files. Most are in auth.rs and relate to
token expiry handling. Two are marked urgent.

Who Selena is for

You run a model locally and you want it to do things — run commands, read and write files, call your scripts — without standing up a Python project to glue it together. You tried a framework, and maintaining agent logic spread across a dozen source files got old.

With Selena, the entire agent lives in one JSON file. Change the model, swap the tools, add a sub-agent, rewrite the system prompt — edit JSON and run again. There is nothing to recompile.

If you're a Rust developer, the same engine ships as a library (selena-core) you can embed directly. That's a secondary path — see docs/EMBEDDING.md.


What Selena is — and isn't

Selena is a runtime: a single binary that reads a config and runs an agent loop against a local model.

It is not:

  • a chat UI or a coding IDE plugin
  • a cloud product or hosted service
  • a Python framework or a LangChain port
  • a model server — it sits on top of Ollama or llama.cpp, it does not run the model itself
  • production-hardened for multi-user or multi-tenant deployments

How it compares

The honest alternatives for the "local model that uses tools" problem:

Selena Python frameworks (LangChain / LlamaIndex) Raw Ollama API loop
Where the agent lives One JSON file Spread across Python source files Your own code
Code to write None Glue, classes, wiring All of it
Tool calling loop Built in Built in You write it
Add a tool Drop a script + manifest in a folder Write a Python class Hand-wire it
Session memory & sub-agents Built in Varies by framework You build it
Runs offline / local-only Yes, by design Usually, with setup Yes
Language / runtime Single Rust binary Python environment Whatever you wrote

Python frameworks target a different ecosystem and are far broader; Selena is narrower on purpose. If you want declarative, local, no-code agents, that narrowness is the point.


Requirements

  • A local model server: Ollama or a llama.cpp server.
  • A model that supports tool calling. This matters — Selena relies on the model emitting tool calls. qwen2.5-coder, llama3.1, and mistral-nemo are reasonable choices; use whatever tool-capable model you have pulled and set model in agent.json to match.
  • The Rust toolchain (1.75+) — only if you build from source. Pre-built binaries for Linux, macOS, and Windows are on the Releases page.

The test suite passes on Linux, macOS, and Windows, and the built-ins are platform-aware: bash runs via sh -c on Unix and PowerShell on Windows, and grep falls back to a pure-Rust search when the external grep binary is absent. See Limitations.


Quick Start

Assumes Ollama is installed and running.

1. Pull a tool-calling model

ollama pull qwen2.5-coder:7b   # any tool-calling model works

2. Get Selena

Download a pre-built binary

Grab the archive for your platform from the Releases page — Linux (x86_64 / aarch64), macOS (Intel / Apple Silicon), and Windows. Extract it and put selena (or selena.exe) somewhere on your PATH. On macOS, if Gatekeeper blocks the unsigned binary, run xattr -d com.apple.quarantine selena.

The archive includes a ready-to-edit agent.json (targeting Ollama on localhost:11434) next to the binary, so a fresh download runs out of the box. Run selena --help to see every command, and selena init (below) to scaffold a project in any directory.

Or build from source

git clone https://github.com/vlune/selena.git
cd selena
cargo build --release

The binary lands at target/release/selena. The first build compiles all dependencies and can take several minutes; later builds are incremental.

3. Scaffold a project (optional)

selena init     # writes agent.json + tools/ + skills/ into the current directory

init is offline — it writes the config compiled into your binary, so it always matches your version. Pass --update to fetch the latest default from GitHub instead, or --force to overwrite an existing agent.json.

4. Run it

./target/release/selena   # or just `selena` if you installed a release binary

No config file is required for the first run — Selena resolves agent.json from the current directory, then next to the binary, then falls back to the built-in default (Ollama on localhost:11434). Edit agent.json to point at your own server or model. You'll get a welcome banner and a prompt:

  selena  v0.2.0 · local-first agentic runtime

  model     qwen2.5-coder:7b
  provider  ollama  http://localhost:11434

  Type a task and press Enter · /help for commands · /quit to exit

›

Output is colorized when stdout is a terminal; set NO_COLOR (or SELENA_NO_COLOR) to disable. Type /help at the prompt for the in-REPL command list.

5. Give it a task

› list the files in this directory and tell me which ones are Rust source files
  ⋯ bash
  ✓ bash
The directory contains Cargo.toml, agent.json, a crates/ directory, and a
target/ directory. The Rust source files live under crates/.

Type /quit or /exit to leave (or press Ctrl-D). Ctrl-C cancels the current turn without exiting.

REPL commands

Anything not starting with / is sent to the agent. Slash commands are handled locally:

Command Does
/help, /? List the commands
/clear Reset the conversation (history + session memory)
/context Show context-window usage and session counters
/tools List the tools available to the agent
/skills List the configured skills
/memory Show session-memory entries
/mode [name] Show the permission modes, or switch live to default / auto_accept / plan / auto / custom
/config [path] Show the active config, or reload from <path> / reload (resets the conversation)
/quit, /exit Leave the REPL

In a real terminal the REPL is a fully async, event-driven line editor: a single crossterm EventStream feeds keystrokes into a tokio::select! loop (nothing blocks the runtime), and each keystroke repaints the input as one batched, flicker-free frame. The usual keys are live:

Key Does
/ , Home / End Move the cursor (also Ctrl-B/Ctrl-F, Ctrl-A/Ctrl-E)
Backspace / Delete Remove the char before / at the cursor (Ctrl-U/Ctrl-K kill to start/end)
/ Walk input history
Shift+Tab At the prompt, cycle the permission presets (default → auto_accept → plan → auto)
Esc / Ctrl-C Interrupt the running turn

When a tool needs approval, an arrow-key menu appears inline: move with / and confirm with Enter, or use the shortcuts — y (yes once), a (always — allow this tool for the rest of the session), or N/Esc (no).


What just happened

Selena ran a loop between the model and your machine:

  1. You sent a message.
  2. The model decided it needed to run a command to answer.
  3. Selena ran the command on your machine and captured the output.
  4. The output went back to the model.
  5. The model answered based on what it saw.

That cycle — model requests a tool, Selena runs it, result returns to the model — repeats until the model is done or the iteration limit is hit. You never paste output back yourself.


Built-in tools

Enable tools by listing them in the tools array. The defaults are:

Tool What it does
bash Run a shell command, return stdout/stderr (sh -c on Unix, PowerShell on Windows)
read_file Read a file's contents
write_file Write content to a file, creating parent directories
edit Replace an exact string in a file (unique match enforced)
glob List files matching a glob pattern (in-process, cross-platform)
grep Search files for a pattern (uses the grep binary when present, pure-Rust fallback otherwise)
webfetch Fetch a URL and return it as text (HTML stripped); native, no external runtime
todowrite / todoread Maintain a shared task list for the current session
store_memory / retrieve_memory Save/read a named value in session memory
remember / recall Persist/read facts across runs (project + global scopes)

Auto-registered when configured: delegate_task / dispatch_parallel (sub-agents), lsp_diagnostics / lsp_hover (LSP), and any MCP server tools.

Full reference, inputs, and outputs: docs/TOOLS.md.

bash runs arbitrary shell commands. Only enable it where that is acceptable, and read docs/SECURITY.md before combining it with auto_accept.


Memory

Within a single run, the model can remember things you tell it (store_memory / retrieve_memory):

› remember that the database password is in .env.production
  ⋯ store_memory
  ✓ store_memory
Stored.

› where is the database password?
  ⋯ retrieve_memory
  ✓ retrieve_memory
You told me it is in .env.production.

That session memory clears when the process exits. For knowledge that should survive restarts, enable persistent memory (memory.persistent.enabled) and use the remember / recall tools — they write markdown to a project store (.selena/memory) or a global store (~/.selena/memory), and the entries are loaded back into the prompt at startup. See docs/CONFIG.md.


Custom tools

Add a tool by dropping a script and a manifest into a tools/ folder — no change to agent.json.

./target/release/selena tools scaffold weather   # generates tools/weather/
# edit tools/weather/weather.sh  (or weather.ps1 on Windows)
./target/release/selena tools doctor             # validate the manifest + script
./target/release/selena tools trust weather      # record its hash and trust it

Run Selena again; the model now has a weather tool. Custom tools run as subprocesses that read JSON arguments on stdin and reply on stdout with {"success": true, "output": "..."}.

When you trust a tool, Selena records a SHA-256 hash of its manifest and script. If either changes, trust is automatically revoked on the next startup. Full manifest format and the trust model: docs/TOOLS.md.


Configuration

Selena reads agent.json from the current directory (override with --config path/to/agent.json). If none is found, a built-in default is used. A fuller example:

{
  "name": "my-agent",
  "provider": "ollama",                 // "ollama", "llamacpp", or "custom" (any OpenAI-compatible API)
  "model": "qwen2.5-coder:7b",
  "system_prompt": "You are a helpful assistant.",
  "tools": ["bash", "read_file", "write_file", "glob", "grep"],
  "skills": ["store_memory", "retrieve_memory"],
  "permission": { "mode": "default" },  // ask before edits/commands (see modes below)
  "inference": {
    "endpoint": "http://localhost:11434",
    "temperature": 0.7,
    "max_tokens": 4096,
    "timeout_secs": 120
  },
  "context": { "max_tokens": 32768, "history_slots": 20, "reserve_output_tokens": 4096 },
  "memory": { "max_segments": 50 },
  "runtime": { "max_iterations": 20 },
  "logging": { "level": "info", "format": "pretty" }
}

permission.mode sets how much the agent does on its own: default (ask before edits/commands), auto_accept (auto-edit, ask before commands), plan (read-only), auto (autonomous — runs anything, including bash, unprompted), or custom (your own per-tool rules; the back-compat default when mode is omitted, honouring the legacy auto_accept). Switch live in the REPL with /mode <name>. With auto mode and bash enabled, the model can run any shell command unprompted. See docs/SECURITY.md.

Every field, type, and default: docs/CONFIG.md.


Limitations

Real gaps. Read them before deciding whether Selena fits.

Limitation Detail
No kernel sandbox sandbox.enabled gives subprocess tools a scrubbed, allowlisted environment (secrets aren't exposed), plus working-dir confinement. But capability labels (network, filesystem, execute) are still not OS-enforced — a tool labelled network: false can reach the network. Kernel isolation (seccomp/landlock, Job Objects) is on the roadmap.
Windows shell needs Git Bash for Unix syntax On Windows the command tools auto-detect a POSIX shell (a Git for Windows bash, then bash/sh on PATH) and use it, so ls -la, &&, etc. work; the WSL launcher (System32\bash.exe) is skipped because it runs in the Linux VM, not the Windows working directory. When none is found they fall back to PowerShell (the prompt's shell hint follows the detected shell either way). grep still prefers the external binary and falls back to a slower pure-Rust search when absent.
No GUI Command-line only.

For Rust developers

selena-core is a library crate with no dependency on the CLI. Embed it directly:

[dependencies]
selena-core = { path = "path/to/selena/crates/selena-core" }
use selena_core::{Core, AgentConfig};

let config = AgentConfig::from_json(include_str!("agent.json"))?;
let mut core = Core::with_config(config)?;   // construction is synchronous
let result = core.turn("summarise the files in /tmp").await?;  // only turn() is async
println!("{}", result.content);

Full API, events, custom providers, and registering tools programmatically: docs/EMBEDDING.md.


Roadmap (short)

Recently shipped: native tool-call schemas for llama.cpp (the request now advertises tools/tool_choice), anchored auto-compaction (rolling conversation summary), Windows-native built-ins (bash via PowerShell, pure-Rust grep fallback), pre-built release binaries (TLS via rustls — no OpenSSL dependency), live MCP client, generic OpenAI-compatible provider, cross-session persistent memory, streaming turn output, interactive ask permissions, parallel + nested sub-agent dispatch, and LSP tools.

Planned: OS-level sandbox enforcement of capability labels, a durable (SQLite/embeddings) persistent-memory backend, and a richer TUI.

Full detail: docs/ROADMAP.md.


Documentation

docs/CONFIG.md Every config field, type, default, and valid value
docs/TOOLS.md Built-in tools, manifest format, trust model
docs/HITL.md Human-in-the-loop pause/resume (hitl_mode, checkpoints)
docs/PROVIDERS.md Ollama vs llama.cpp, tool-calling behavior, inspect-provider
docs/SECURITY.md What is and isn't enforced, audit logging, risks
docs/EMBEDDING.md Using selena-core as a Rust library
docs/EXAMPLES.md Copy-paste agent configurations
docs/TROUBLESHOOTING.md Common failures and fixes
docs/FAQ.md Common questions
docs/ARCHITECTURE.md Internal design for contributors
docs/ROADMAP.md Built, in progress, and planned
docs/CONTRIBUTING.md How to contribute

License

Licensed under the Apache-2.0 License.

About

Agent orchestration framework that manages AI workflows through configuration instead of code. Define tools, memory, providers, and execution flow with portable JSON configs.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages