# Uracil

A hardware-agnostic, rootless microkernel runtime for native services.

Uracil provides a minimal, capability-scoped execution environment for service bundles. Each bundle declares the permissions it needs; users grant only what they approve. The runtime refuses to execute any function whose requirements haven't been satisfied.

```
                        ┌──────────────────────────────────────┐
                        │           uracil runtime             │
                        ├──────────────┬───────────────────────┤
                        │  permission  │     bundle loader     │
                        │    engine    │  (JSON manifest → C)  │
                        ├──────────────┼───────────────────────┤
                        │  grant store │  subprocess executor  │
                        │ ~/.uracil/   │  (fork+exec python3)  │
                        ├──────────────┴───────────────────────┤
                        │       host platform adapter          │
                        │         (arch/host/)                 │
                        └──────────────────────────────────────┘
```

## Features

- **Permission model** — services declare capabilities; users grant them explicitly
- **Bundle manifest** — JSON contract describing service identity, functions, and permissions
- **External bundle loader** — load any APS-installed service directory at runtime
- **Subprocess executor** — run function snippets as isolated child processes
- **Built-in JSON parser** — zero-dependency manifest loading
- **Hot-swap metadata** — versioned payload groups for safe service updates
- **Runner metadata passthrough** — `.ura` bundles can carry GGUF/API runner metadata for Athena-managed model services
- **Campaign kernel** — persistent campaign-scoped state, artifact ownership, and cleanup under `~/.uracil/campaigns/`
- **Host-first** — works on Linux x86_64 now, designed for additional ISAs later
- **C11, zero external dependencies** — only libc and POSIX

## Build

Requires CMake 3.20+ and a C11 compiler (GCC or Clang).

```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
```

Run the test suite:

```bash
ctest --test-dir build --output-on-failure
```

## Usage

### Built-in demo bundle

The binary ships with a compiled-in sample service so the runtime is usable immediately:

```bash
$ ./build/uracil describe
service:         aps.sample.echo-service
version:         0.1.0
description:     Sample APS-native service bundle running inside Uracil.
runtime abi:     uracil.service.v1
hot-swap group:  aps.sample.echo-service
payload rev:     demo-001
rootless:        true
requested perms: fs.read, net.client, clock.read

$ ./build/uracil grant fs.read clock.read
updated grant manifest: fs.read, clock.read

$ ./build/uracil run clock-now
virtual clock reading: 2026-04-17 12:00:00 UTC
```

### External bundles (APS packages)

Load any service directory that contains a `manifest.json`:

```bash
# Describe an APS-installed service
./build/uracil --bundle ~/.aps/packages/weather-check-service describe

# Grant permissions
./build/uracil --bundle ~/.aps/packages/weather-check-service grant net.client

# Run a function (executes functions/current_weather.py as a subprocess)
./build/uracil --bundle ~/.aps/packages/weather-check-service run current-weather London

# Check permission state
./build/uracil --bundle ~/.aps/packages/weather-check-service permissions
```

The `--bundle` flag switches from the compiled demo to an external service. The runtime:

1. Reads `manifest.json` from the directory
2. Validates the bundle contract (name, version, ABI, functions)
3. Applies the same permission model as compiled bundles
4. Executes function snippets via `python3 functions/<name>.py`
5. Sets `URACIL_*` environment variables for the subprocess

### Campaign kernel

Uracil exposes a persistent campaign-kernel surface for multi-step coordinators and agent harnesses. Each campaign gets its own runtime root under `~/.uracil/campaigns/<campaign-id>/`, including an `artifacts/` directory for owned binaries and payloads that are cleaned up when the campaign finishes.

```bash
# Bootstrap a campaign runtime root
./build/uracil campaign init demo-campaign keryx keryx-ami adeno-cauth

# Attach a generated artifact for later cleanup
./build/uracil campaign attach-artifact demo-campaign artifacts/writer.ura

# Transition to running
./build/uracil campaign start demo-campaign

# Complete the campaign and clean registered artifacts
./build/uracil campaign complete demo-campaign

# Remove the campaign kernel state entirely
./build/uracil campaign destroy demo-campaign
```

## Permission Model

Uracil separates **declared capabilities** from **user-granted permissions**.

A service bundle's manifest lists every permission the service might need:

```json
{
  "permissions": {
    "requested": ["fs.read", "net.client", "clock.read"]
  }
}
```

Each function declares which subset it actually requires:

```json
{
  "name": "current-weather",
  "description": "Fetch current weather for a city",
  "required_permissions": ["net.client"]
}
```

The runtime will only execute a function if **every** permission in its `required_permissions` has been granted by the user. Grants are stored locally in `~/.uracil/grants/<service-name>.perm`.

### Available permissions

| Permission     | Capability                        |
|----------------|-----------------------------------|
| `fs.read`      | Read files from the host          |
| `fs.write`     | Write files to the host           |
| `net.client`   | Make outbound network connections |
| `net.server`   | Listen for inbound connections    |
| `proc.spawn`   | Spawn child processes             |
| `clock.read`   | Read the system clock             |

### Grant lifecycle

```bash
# View what's requested vs. granted
uracil --bundle <dir> permissions

# Grant specific permissions
uracil --bundle <dir> grant net.client clock.read

# Revoke a permission
uracil --bundle <dir> revoke net.client

# The runtime refuses to run functions with unmet requirements
uracil --bundle <dir> run current-weather   # → permission-denied
```

## Bundle Manifest

Every service bundle carries a `manifest.json` at its root:

```json
{
  "name": "weather-check-service",
  "version": "0.1.0",
  "description": "Fetches weather through a permission-scoped function",
  "runtime": {
    "name": "uracil",
    "abi": "uracil.service.v1",
    "mode": "rootless",
    "hotswap_group": "weather-check-service",
    "payload_revision": "0.1.0",
    "target_env": "keryx-ami"
  },
  "security": {
    "cauth": {
      "enabled": true,
      "mode": "adeno-cauth",
      "base_url": "https://adeno.ltd/cauth",
      "issuer": "https://adeno.ltd/cauth",
      "audience": "keryx",
      "token_env": "KERYX_TRANSTOKEN",
      "secret_key_env": "CAUTH_SECRET_KEY"
    }
  },
  "service": {
    "entry_function": "current-weather",
    "functions": [
      {
        "name": "current-weather",
        "description": "Fetch current weather for a city",
        "snippet_path": "functions/current_weather.py",
        "required_permissions": ["net.client"]
      },
      {
        "name": "inspect-fs-native",
        "description": "List the working directory with a native helper",
        "snippet_path": "functions/inspect_fs.cpp",
        "language": "cpp",
        "build": { "standard": "c++20", "flags": ["-O3"] },
        "required_permissions": ["fs.read"]
      }
    ]
  },
  "permissions": {
    "requested": ["fs.read", "net.client", "clock.read"]
  }
}
```

### Manifest fields

| Field | Required | Description |
|-------|----------|-------------|
| `name` | Yes | Globally unique service identifier |
| `version` | Yes | Semantic version |
| `description` | No | Human-readable summary |
| `runtime.name` | No | Runtime target (`uracil`) |
| `runtime.abi` | No | ABI version (`uracil.service.v1`) |
| `runtime.mode` | No | Execution mode (`rootless`) |
| `runtime.hotswap_group` | No | Group ID for safe payload updates |
| `runtime.payload_revision` | No | Current payload version |
| `runtime.target_env` | No | Deployment profile such as `keryx-ami` |
| `security.cauth` | No | CAuth runtime metadata projected as `URACIL_CAUTH_*` |
| `service.entry_function` | No | Default function to run |
| `service.functions[]` | No | Array of function descriptors |
| `service.functions[].language` | No | `python` (default) or `cpp` for native functions |
| `service.functions[].build` | No | Optional native compile options |
| `service.functions[].binary_path` | No | Prebuilt native binary path for compiled `.ura` bundles |
| `permissions.requested` | No | Union of all permissions the service needs |

## Subprocess Execution

When running an external bundle, Uracil executes function payloads as child processes:

```
uracil --bundle <dir> run <function> [args...]
       │
       ├── fork()
       │
       └── child:
           chdir(<service_directory>)
           setenv(URACIL_SERVICE_NAME, ...)
           setenv(URACIL_GRANTED_PERMISSIONS, ...)
           exec("python3", "functions/<function>.py", args...)   # Python
           exec("compiled/<function>", args...)                  # Native C++
```

### Environment variables

| Variable | Description |
|----------|-------------|
| `URACIL_SERVICE_NAME` | Service identifier from manifest |
| `URACIL_SERVICE_VERSION` | Version string |
| `URACIL_FUNCTION_NAME` | Name of the function being executed |
| `URACIL_RUNTIME_ABI` | ABI version |
| `URACIL_HOTSWAP_GROUP` | Hot-swap group identifier |
| `URACIL_PAYLOAD_REVISION` | Current payload revision |
| `URACIL_TARGET_ENV` | Deployment profile such as `keryx-ami` |
| `URACIL_SERVICE_DIR` | Absolute path to the service directory |
| `URACIL_STATE_DIR` | Path to `~/.uracil` |
| `URACIL_ROOTLESS` | Always `true` in rootless mode |
| `URACIL_REQUESTED_PERMISSIONS` | Comma-separated list |
| `URACIL_GRANTED_PERMISSIONS` | Comma-separated list |
| `URACIL_CAUTH_*` | Adeno CAuth runtime contract for token and envelope metadata |
| `URACIL_RUNNER_*` | GGUF/API runner contract exposed to snippets and compiled `.ura` binaries |

## APS Integration

Uracil is designed as a runtime target for the [APS](/products/aps/) package ecosystem:

```
  ┌─────────────┐    codegen     ┌────────────────┐
  │    Keryx     │──────────────→│  .aps archive   │
  │  (Devstral)  │               │  manifest.json  │
  └─────────────┘               │  functions/*.py │
                                 └───────┬────────┘
                                         │ aps install service
                                         ▼
                                 ┌────────────────┐
                                 │  APS registry   │
                                 │  ~/.aps/pkgs/   │
                                 └───────┬────────┘
                                         │ uracil --bundle
                                         ▼
                                 ┌────────────────┐
                                 │    Uracil       │
                                 │  permission ──→ │ grant/deny
                                 │  subprocess ──→ │ execute
                                 └────────────────┘
```

Typical workflow:

```bash
aps install service weather-check-service
aps audit weather-check-service            # inspect locally without exposing secrets
uracil --bundle ~/.aps/packages/weather-check-service describe
uracil --bundle ~/.aps/packages/weather-check-service grant net.client
uracil --bundle ~/.aps/packages/weather-check-service run current-weather London
```

### GGUF service runners

Athena packages model-backed services as APS bundles first, then compiles them into `.ura` binaries. For GGUF-backed services, include runner metadata in the manifest so the URA artifact carries the model contract alongside the function definitions:

```json
{
  "runner": {
    "kind": "gguf-http",
    "protocol": "http",
    "bind": "127.0.0.1:8088",
    "model": {
      "format": "gguf",
      "uri": "corpus://athena/models/mistral-7b-instruct.gguf"
    }
  }
}
```

For virtualized accelerator targets, keep the source model in GGUF while declaring the runtime target separately:

```json
{
  "runner": {
    "kind": "gguf-neuron",
    "protocol": "http",
    "bind": "127.0.0.1:8091",
    "model": {
      "format": "gguf",
      "uri": "corpus://athena/models/mistral-7b-instruct.gguf"
    },
    "virtualization": {
      "target": "aws-neuron-inf2",
      "accelerator": "neuron",
      "source_format": "gguf",
      "runtime_format": "neff"
    }
  }
}
```

Both execution paths expose this contract to snippets via `URACIL_RUNNER_*` environment variables.

## Architecture

### Two-tier design

1. **C core** (`kernel/` + `arch/host/`) — compiled binary with embedded demo bundle demonstrating the permission engine, grant store, and function dispatch in native code.
2. **External loader** — loads service bundles from JSON manifests at runtime and executes function snippets as subprocesses. This is the path APS-installed packages take.

Both tiers share the same permission model (requested → granted → enforced), the same grant store, the same bundle descriptor structure, and the same CLI interface.

### Design principles

- **Capability-scoped** — no ambient authority; every function must declare what it needs.
- **Rootless** — no elevated privileges; services run as the current user.
- **Host-first** — establish the contract on Linux, then port to other targets.
- **Zero dependencies** — the C runtime needs only libc and POSIX.
- **Hot-swap ready** — payload revisions within a group can be updated safely.
