# Spens 
Spens is a toolchain that helps run and orchistrate agents in a safe environment with full audit control. It is not designed to be 100% secure, but secure enough for most workloads. 

## Why Spens Exists
I work in windows and across many code bases, as well as expirement with several agents and llms. I needed a simple way to move around agents and llms without polluting my computer or creating conflcits. It is built ontop of Docker and Nono.sh and LLMInterceptor as the three tools when combined creates reproducable, observable agent runtimes without a ton of customization. 

## How Agents Run. 
Agents run inside a docker instance with a nono shell. All network traffic is proxied through a sidecar interceptor that is intercepting traffic and saving llm traces. Traces and nono shell infromation is saved down to .spens/session/[session_id].

## How Spens works. 
Spens is powered by environment and agent configurations. These configurations exist in templates/* . The environment configuration defines the agent base image, packages to install and command to install nono. The agent template defines how to install the agent, how to make sure the binarys are available, and during runtime what to mount as a configuration from the host machine. 

Finally there is an option spens configuration file (and example lives in .spens.config.json) , this file enables the abiltiy to override the nono.sh profile with a user supplied file, as well as define any additional urls to trace. It has the following paremeters. 
nono_override: a path to a file that is used for the nono profile, over the default created one. 
addition_capture_urls: an array of urls to also capture traces on 
env: an array of environment vairables to forward from the current session

A user invokes spens with the following command 

```bash
spens node-12 opencode . 
```

The first arg is the environment, the second arg is the agent the thrid arg is the workspace. If a .spens.config.json is in the same folder that is also read. 

An optional fourth argument is a prompt, which runs the agent in yolo (non-interactive) mode:

```bash
spens node-12 opencode . "refactor the parser module"
```

Each agent template defines a `yolo_command` with a `{prompt}` placeholder (e.g. `opencode run --auto {prompt}`). When a prompt is supplied on the CLI it is passed into the container as the `SPENS_YOLO_PROMPT` environment variable, and the entrypoint runs the resolved `yolo_command` instead of the interactive agent. If the agent template has no `yolo_command`, passing a prompt is an error.

### Workflow
Specfically when you run spens the following things happen: 

1. A docker image is created for the agent. This docker image does the following: 
  1. users the base image from the environment
  2. collects all the packages from the envionrment and agent, and installs them. It determins the package manager through the environment configuration 
  3. runs the nono.sh install. 
  4. runs any dependencies commands for the agent 
  5. runs the installation command for the agent 
  6. creates a nono-profile based on the two provided nono base profiles OR if a file was provided in the configuration copys that 
  7. sets the envionment variables to use the HTTP/HTTPS proxy as well as mount the cert from the cert store
  7. creates the command to run the nono shell with the allowed files (as defined in the agent template) and the proper profile
2. Creates a second docker image that
  1. installs LLM Interceptor
  2. generates the certiifcate 
  3. runs it with any additional taces from the spens config
3. Executes the second docker image (LLM Interceptor) and waits for the cert, also mounts the traces folder to .spens/sessions/[uniqueid]/traces
4. Once certs are created, it executes the second docker image with the nono audit mounted and the correct environment variables. Any additional evnrionment variables listed in .spens.config.json are mapped forward. 

### Tech 
Python is used for the base spens tool
[nono.sh ](https://nono.sh/) is used for the nono shell
docker for the runtime
https://github.com/chouzz/llm-interceptor is used for the Proxy
