mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-31 03:12:16 +00:00
Add MkDocs Material documentation site with 40 pages and auto-generated API reference
Sets up a complete documentation website with 7 navigable sections (Home, Getting Started, User Guide, Architecture, API Reference, Deployment, Development), light/dark mode, search, code copy, and Mermaid diagram support. API reference pages use mkdocstrings to auto-generate docs from source docstrings. GitHub Actions workflow deploys to GitHub Pages on push to main. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
990d7d8a79
commit
f75afefcfb
@@ -0,0 +1,455 @@
|
||||
# API Server
|
||||
|
||||
OpenJarvis includes an OpenAI-compatible API server built on FastAPI and uvicorn. It exposes chat completion, model listing, and health check endpoints, making it a drop-in replacement for the OpenAI API when working with local models.
|
||||
|
||||
## Starting the Server
|
||||
|
||||
The server requires the `[server]` extra (FastAPI + uvicorn):
|
||||
|
||||
```bash
|
||||
pip install 'openjarvis[server]'
|
||||
```
|
||||
|
||||
Start with default settings:
|
||||
|
||||
```bash
|
||||
jarvis serve
|
||||
```
|
||||
|
||||
The server reads defaults from `~/.openjarvis/config.toml` and auto-detects available engines and models. Override any option via CLI flags:
|
||||
|
||||
```bash
|
||||
jarvis serve --host 0.0.0.0 --port 8000 --engine ollama --model qwen3:8b --agent orchestrator
|
||||
```
|
||||
|
||||
### CLI Options
|
||||
|
||||
| Option | Description | Default |
|
||||
|----------------------|------------------------------------------------------------------------------|--------------------|
|
||||
| `--host` | Network address to bind to | From config (`0.0.0.0`) |
|
||||
| `--port` | Port number to listen on | From config (`8000`) |
|
||||
| `-e` / `--engine` | Inference engine backend (`ollama`, `vllm`, `llamacpp`, `sglang`) | Auto-detected |
|
||||
| `-m` / `--model` | Default model for completions | First available |
|
||||
| `-a` / `--agent` | Agent for non-streaming requests (`simple`, `orchestrator`, `react`, `openhands`) | From config (`orchestrator`) |
|
||||
|
||||
On startup, the server prints a summary:
|
||||
|
||||
```
|
||||
Starting OpenJarvis API server
|
||||
Engine: ollama
|
||||
Model: qwen3:8b
|
||||
Agent: orchestrator
|
||||
URL: http://0.0.0.0:8000
|
||||
```
|
||||
|
||||
!!! warning "Server dependency check"
|
||||
If the `[server]` extra is not installed, `jarvis serve` exits with a clear error message explaining how to install the required dependencies.
|
||||
|
||||
## Endpoints
|
||||
|
||||
### `POST /v1/chat/completions`
|
||||
|
||||
The primary endpoint for generating chat completions. Accepts the same request format as the OpenAI Chat Completions API.
|
||||
|
||||
#### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "qwen3:8b",
|
||||
"messages": [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "What is the capital of France?"}
|
||||
],
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 1024,
|
||||
"stream": false,
|
||||
"tools": null
|
||||
}
|
||||
```
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---------------|-------------------|---------|--------------------------------------------------------------|
|
||||
| `model` | `string` | -- | **Required.** Model identifier to use for generation. |
|
||||
| `messages` | `array` | -- | **Required.** Array of message objects with `role` and `content`. |
|
||||
| `temperature` | `float` | `0.7` | Sampling temperature (0.0 to 2.0). |
|
||||
| `max_tokens` | `integer` | `1024` | Maximum number of tokens to generate. |
|
||||
| `stream` | `boolean` | `false` | Whether to stream the response via SSE. |
|
||||
| `tools` | `array` or `null` | `null` | Tool definitions in OpenAI function-calling format. |
|
||||
|
||||
Each message object:
|
||||
|
||||
| Field | Type | Description |
|
||||
|----------------|-------------------|-------------------------------------------------------|
|
||||
| `role` | `string` | One of `system`, `user`, `assistant`, or `tool`. |
|
||||
| `content` | `string` | The message content. |
|
||||
| `name` | `string` or `null`| Optional name for the message author. |
|
||||
| `tool_calls` | `array` or `null` | Tool calls made by the assistant (in assistant messages). |
|
||||
| `tool_call_id` | `string` or `null`| ID of the tool call this message responds to (in tool messages). |
|
||||
|
||||
#### Response (Non-Streaming)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "chatcmpl-abc123def456",
|
||||
"object": "chat.completion",
|
||||
"created": 1740100800,
|
||||
"model": "qwen3:8b",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": "The capital of France is Paris.",
|
||||
"tool_calls": null
|
||||
},
|
||||
"finish_reason": "stop"
|
||||
}
|
||||
],
|
||||
"usage": {
|
||||
"prompt_tokens": 25,
|
||||
"completion_tokens": 8,
|
||||
"total_tokens": 33
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When an agent is configured on the server, non-streaming requests are routed through the agent, which can perform multi-turn reasoning with tool calls before returning a final response. When no agent is configured, requests go directly to the inference engine.
|
||||
|
||||
#### Tool Calls
|
||||
|
||||
When `tools` are provided in the request, the engine may return `tool_calls` in the assistant message:
|
||||
|
||||
```json
|
||||
{
|
||||
"choices": [
|
||||
{
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": "",
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_abc123",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "calculator",
|
||||
"arguments": "{\"expression\": \"2 + 2\"}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"finish_reason": "tool_calls"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /v1/models`
|
||||
|
||||
Lists all models available on the configured inference engine.
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "qwen3:8b",
|
||||
"object": "model",
|
||||
"created": 1740100800,
|
||||
"owned_by": "openjarvis"
|
||||
},
|
||||
{
|
||||
"id": "llama3.1:8b",
|
||||
"object": "model",
|
||||
"created": 1740100800,
|
||||
"owned_by": "openjarvis"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /health`
|
||||
|
||||
Health check endpoint that verifies the inference engine is responsive.
|
||||
|
||||
#### Response (Healthy)
|
||||
|
||||
HTTP 200:
|
||||
|
||||
```json
|
||||
{"status": "ok"}
|
||||
```
|
||||
|
||||
#### Response (Unhealthy)
|
||||
|
||||
HTTP 503:
|
||||
|
||||
```json
|
||||
{"detail": "Engine unhealthy"}
|
||||
```
|
||||
|
||||
### `GET /dashboard`
|
||||
|
||||
Serves the built-in Savings Dashboard, an HTML page that displays real-time statistics on inference calls served locally and estimated cost savings compared to cloud API providers. The dashboard auto-refreshes every 5 seconds by polling the `/v1/savings` endpoint.
|
||||
|
||||
## Streaming via SSE
|
||||
|
||||
When `"stream": true` is set in the request, the server returns a `text/event-stream` response using Server-Sent Events (SSE). The response follows the same format as the OpenAI streaming API.
|
||||
|
||||
Each event is a `data:` line containing a JSON chunk, followed by a blank line:
|
||||
|
||||
```
|
||||
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1740100800,"model":"qwen3:8b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
|
||||
|
||||
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1740100800,"model":"qwen3:8b","choices":[{"index":0,"delta":{"content":"The"},"finish_reason":null}]}
|
||||
|
||||
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1740100800,"model":"qwen3:8b","choices":[{"index":0,"delta":{"content":" capital"},"finish_reason":null}]}
|
||||
|
||||
...
|
||||
|
||||
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1740100800,"model":"qwen3:8b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
|
||||
|
||||
data: [DONE]
|
||||
```
|
||||
|
||||
The stream follows this sequence:
|
||||
|
||||
1. **Role chunk** -- first chunk contains `"delta": {"role": "assistant"}` with no content.
|
||||
2. **Content chunks** -- subsequent chunks each contain a `"delta": {"content": "..."}` with one or more tokens.
|
||||
3. **Finish chunk** -- a chunk with an empty `delta` and `"finish_reason": "stop"`.
|
||||
4. **Done signal** -- the literal string `data: [DONE]` indicates the stream is complete.
|
||||
|
||||
Response headers include `Cache-Control: no-cache` and `Connection: keep-alive` for proper SSE behavior.
|
||||
|
||||
## Client Examples
|
||||
|
||||
=== "curl"
|
||||
|
||||
**Non-streaming request:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "qwen3:8b",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Explain quantum computing in one paragraph."}
|
||||
],
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 256
|
||||
}'
|
||||
```
|
||||
|
||||
**Streaming request:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-N \
|
||||
-d '{
|
||||
"model": "qwen3:8b",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Write a haiku about programming."}
|
||||
],
|
||||
"stream": true
|
||||
}'
|
||||
```
|
||||
|
||||
**List models:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/v1/models
|
||||
```
|
||||
|
||||
**Health check:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
=== "Python (openai)"
|
||||
|
||||
The OpenAI Python library works as a drop-in client by pointing `base_url` at the local server:
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(
|
||||
base_url="http://localhost:8000/v1",
|
||||
api_key="not-needed", # Required by the library but not validated
|
||||
)
|
||||
|
||||
# Non-streaming
|
||||
response = client.chat.completions.create(
|
||||
model="qwen3:8b",
|
||||
messages=[
|
||||
{"role": "user", "content": "What is the capital of France?"}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=256,
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
|
||||
# Streaming
|
||||
stream = client.chat.completions.create(
|
||||
model="qwen3:8b",
|
||||
messages=[
|
||||
{"role": "user", "content": "Write a short poem about AI."}
|
||||
],
|
||||
stream=True,
|
||||
)
|
||||
for chunk in stream:
|
||||
if chunk.choices[0].delta.content:
|
||||
print(chunk.choices[0].delta.content, end="", flush=True)
|
||||
print()
|
||||
|
||||
# List models
|
||||
models = client.models.list()
|
||||
for model in models.data:
|
||||
print(model.id)
|
||||
```
|
||||
|
||||
=== "Python (httpx)"
|
||||
|
||||
Using `httpx` for direct HTTP requests:
|
||||
|
||||
```python
|
||||
import httpx
|
||||
import json
|
||||
|
||||
BASE_URL = "http://localhost:8000"
|
||||
|
||||
# Non-streaming request
|
||||
response = httpx.post(
|
||||
f"{BASE_URL}/v1/chat/completions",
|
||||
json={
|
||||
"model": "qwen3:8b",
|
||||
"messages": [
|
||||
{"role": "user", "content": "What is the capital of France?"}
|
||||
],
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 256,
|
||||
},
|
||||
)
|
||||
data = response.json()
|
||||
print(data["choices"][0]["message"]["content"])
|
||||
|
||||
# Streaming request
|
||||
with httpx.stream(
|
||||
"POST",
|
||||
f"{BASE_URL}/v1/chat/completions",
|
||||
json={
|
||||
"model": "qwen3:8b",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Write a haiku about code."}
|
||||
],
|
||||
"stream": True,
|
||||
},
|
||||
) as response:
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data: ") and line != "data: [DONE]":
|
||||
chunk = json.loads(line[6:])
|
||||
content = chunk["choices"][0]["delta"].get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
print()
|
||||
|
||||
# List models
|
||||
response = httpx.get(f"{BASE_URL}/v1/models")
|
||||
for model in response.json()["data"]:
|
||||
print(model["id"])
|
||||
|
||||
# Health check
|
||||
response = httpx.get(f"{BASE_URL}/health")
|
||||
print(response.json())
|
||||
```
|
||||
|
||||
## Configuration via `config.toml`
|
||||
|
||||
The `[server]` section of `~/.openjarvis/config.toml` controls default server behavior:
|
||||
|
||||
```toml
|
||||
[server]
|
||||
host = "0.0.0.0"
|
||||
port = 8000
|
||||
agent = "orchestrator"
|
||||
model = ""
|
||||
workers = 1
|
||||
```
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----------|-----------|-----------------|----------------------------------------------------------------------------|
|
||||
| `host` | `string` | `"0.0.0.0"` | Network address to bind to. Use `"127.0.0.1"` for localhost-only access. |
|
||||
| `port` | `integer` | `8000` | Port number. |
|
||||
| `agent` | `string` | `"orchestrator"`| Default agent for non-streaming requests. Set to `""` for direct engine mode. |
|
||||
| `model` | `string` | `""` | Default model name. When empty, falls back to `[intelligence] default_model` or the first model discovered on the engine. |
|
||||
| `workers` | `integer` | `1` | Number of uvicorn workers (for future use). |
|
||||
|
||||
CLI flags override config file values. For example, `jarvis serve --port 9000` overrides the `port` setting in the config file.
|
||||
|
||||
The server also reads from other config sections at startup:
|
||||
|
||||
- **`[engine]`** -- determines which inference backend to connect to and its host URL.
|
||||
- **`[intelligence]`** -- provides the fallback `default_model` when no model is specified.
|
||||
- **`[agent]`** -- supplies `max_turns` for multi-turn agents like `orchestrator`.
|
||||
|
||||
## Running Behind a Reverse Proxy
|
||||
|
||||
For production deployments, run OpenJarvis behind a reverse proxy like Nginx or Caddy for TLS termination, rate limiting, and authentication.
|
||||
|
||||
### Nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name jarvis.example.com;
|
||||
|
||||
ssl_certificate /etc/ssl/certs/jarvis.pem;
|
||||
ssl_certificate_key /etc/ssl/private/jarvis.key;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# SSE streaming support
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! important "Disable buffering for SSE"
|
||||
The `proxy_buffering off` directive is critical for streaming responses. Without it, Nginx buffers the SSE chunks and delivers them in batches, defeating the purpose of streaming.
|
||||
|
||||
### Caddy
|
||||
|
||||
```
|
||||
jarvis.example.com {
|
||||
reverse_proxy 127.0.0.1:8000 {
|
||||
flush_interval -1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `flush_interval -1` setting disables response buffering, which is required for SSE streaming.
|
||||
|
||||
### Bind to Localhost
|
||||
|
||||
When running behind a reverse proxy, bind the server to `127.0.0.1` so it only accepts connections from the proxy:
|
||||
|
||||
```bash
|
||||
jarvis serve --host 127.0.0.1 --port 8000
|
||||
```
|
||||
|
||||
Or in `config.toml`:
|
||||
|
||||
```toml
|
||||
[server]
|
||||
host = "127.0.0.1"
|
||||
port = 8000
|
||||
```
|
||||
@@ -0,0 +1,337 @@
|
||||
# Docker Deployment
|
||||
|
||||
OpenJarvis provides Docker images for both CPU-only and GPU-accelerated deployments, along with a Docker Compose configuration that bundles the API server with an Ollama inference backend.
|
||||
|
||||
## Quick Start
|
||||
|
||||
The fastest way to get OpenJarvis running in Docker is with Docker Compose, which starts both the API server and an Ollama backend:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
This brings up two services:
|
||||
|
||||
| Service | Port | Description |
|
||||
|----------|-------|------------------------------------|
|
||||
| `jarvis` | 8000 | OpenJarvis API server |
|
||||
| `ollama` | 11434 | Ollama inference engine |
|
||||
|
||||
Verify the server is running:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
Expected response:
|
||||
|
||||
```json
|
||||
{"status": "ok"}
|
||||
```
|
||||
|
||||
## Docker Images
|
||||
|
||||
### CPU-Only Image (`Dockerfile`)
|
||||
|
||||
The default `Dockerfile` uses a multi-stage build based on `python:3.12-slim` to produce a minimal image.
|
||||
|
||||
**Build stages:**
|
||||
|
||||
1. **Builder stage** -- installs `uv` and the `openjarvis[server]` package (which includes FastAPI, uvicorn, and all server dependencies) from the project source.
|
||||
2. **Runtime stage** -- copies only the installed Python packages and application code from the builder, keeping the final image small.
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.12-slim AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY src/ src/
|
||||
|
||||
RUN pip install --no-cache-dir uv && \
|
||||
uv pip install --system ".[server]"
|
||||
|
||||
FROM python:3.12-slim
|
||||
|
||||
COPY --from=builder /usr/local /usr/local
|
||||
COPY --from=builder /app /app
|
||||
WORKDIR /app
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT ["jarvis"]
|
||||
CMD ["serve", "--host", "0.0.0.0", "--port", "8000"]
|
||||
```
|
||||
|
||||
Build it manually:
|
||||
|
||||
```bash
|
||||
docker build -t openjarvis:latest .
|
||||
```
|
||||
|
||||
Run it standalone:
|
||||
|
||||
```bash
|
||||
docker run -d -p 8000:8000 openjarvis:latest
|
||||
```
|
||||
|
||||
### GPU Image (`Dockerfile.gpu`)
|
||||
|
||||
The GPU image is built on `nvidia/cuda:12.4.0-runtime-ubuntu22.04` and includes the CUDA 12.4 runtime libraries, enabling GPU-accelerated inference when paired with a GPU-capable engine like vLLM or SGLang.
|
||||
|
||||
```dockerfile
|
||||
FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04 AS builder
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends python3 python3-pip python3-venv && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY src/ src/
|
||||
|
||||
RUN pip install --no-cache-dir uv && \
|
||||
uv pip install --system ".[server]"
|
||||
|
||||
FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends python3 python3-pip && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /usr/local /usr/local
|
||||
COPY --from=builder /app /app
|
||||
WORKDIR /app
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT ["jarvis"]
|
||||
CMD ["serve", "--host", "0.0.0.0", "--port", "8000"]
|
||||
```
|
||||
|
||||
Build the GPU image:
|
||||
|
||||
```bash
|
||||
docker build -f Dockerfile.gpu -t openjarvis:gpu .
|
||||
```
|
||||
|
||||
Run with GPU access (requires the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)):
|
||||
|
||||
```bash
|
||||
docker run -d --gpus all -p 8000:8000 openjarvis:gpu
|
||||
```
|
||||
|
||||
!!! note "NVIDIA Container Toolkit required"
|
||||
The host machine must have the NVIDIA Container Toolkit installed for `--gpus` to work. See the [NVIDIA installation guide](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) for setup instructions.
|
||||
|
||||
## Docker Compose Configuration
|
||||
|
||||
The `docker-compose.yml` defines a complete deployment with the OpenJarvis API server and an Ollama backend:
|
||||
|
||||
```yaml
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
jarvis:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
- OPENJARVIS_ENGINE_DEFAULT=ollama
|
||||
- OPENJARVIS_OLLAMA_HOST=http://ollama:11434
|
||||
depends_on:
|
||||
- ollama
|
||||
restart: unless-stopped
|
||||
|
||||
ollama:
|
||||
image: ollama/ollama
|
||||
ports:
|
||||
- "11434:11434"
|
||||
volumes:
|
||||
- ollama-models:/root/.ollama
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
ollama-models:
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The `jarvis` service is configured through environment variables:
|
||||
|
||||
| Variable | Description | Default |
|
||||
|-------------------------------|---------------------------------------------------------|----------------------------|
|
||||
| `OPENJARVIS_ENGINE_DEFAULT` | Inference engine backend to use | `ollama` |
|
||||
| `OPENJARVIS_OLLAMA_HOST` | URL of the Ollama server (uses Docker service name) | `http://ollama:11434` |
|
||||
|
||||
### Volumes
|
||||
|
||||
The `ollama-models` named volume persists downloaded models across container restarts, so models do not need to be re-pulled after a `docker compose down` / `docker compose up` cycle.
|
||||
|
||||
### Service Dependencies
|
||||
|
||||
The `jarvis` service declares `depends_on: ollama`, ensuring the Ollama container starts before the API server. Both services use `restart: unless-stopped` to automatically recover from crashes.
|
||||
|
||||
## Custom Configuration
|
||||
|
||||
### Mounting a Configuration File
|
||||
|
||||
To use a custom `config.toml`, mount it into the container at the expected path (`~/.openjarvis/config.toml`, which is `/root/.openjarvis/config.toml` in the container):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jarvis:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./my-config.toml:/root/.openjarvis/config.toml:ro
|
||||
environment:
|
||||
- OPENJARVIS_ENGINE_DEFAULT=ollama
|
||||
- OPENJARVIS_OLLAMA_HOST=http://ollama:11434
|
||||
depends_on:
|
||||
- ollama
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### Persisting Data
|
||||
|
||||
To persist telemetry data, memory databases, and trace records across container restarts, mount the entire OpenJarvis data directory:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jarvis:
|
||||
# ... other config ...
|
||||
volumes:
|
||||
- openjarvis-data:/root/.openjarvis
|
||||
|
||||
volumes:
|
||||
ollama-models:
|
||||
openjarvis-data:
|
||||
```
|
||||
|
||||
This preserves:
|
||||
|
||||
- `telemetry.db` -- inference call telemetry records
|
||||
- `memory.db` -- the default SQLite memory backend
|
||||
- `traces.db` -- interaction trace records
|
||||
- `config.toml` -- user configuration
|
||||
|
||||
### Using the GPU Image with Compose
|
||||
|
||||
To use the GPU Dockerfile in your Compose setup, change the `dockerfile` field and add GPU resource reservations:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jarvis:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.gpu
|
||||
ports:
|
||||
- "8000:8000"
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
environment:
|
||||
- OPENJARVIS_ENGINE_DEFAULT=ollama
|
||||
- OPENJARVIS_OLLAMA_HOST=http://ollama:11434
|
||||
depends_on:
|
||||
- ollama
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
## Health Check
|
||||
|
||||
The API server exposes a `GET /health` endpoint that checks whether the underlying inference engine is responsive:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
A healthy response returns HTTP 200:
|
||||
|
||||
```json
|
||||
{"status": "ok"}
|
||||
```
|
||||
|
||||
An unhealthy engine returns HTTP 503:
|
||||
|
||||
```json
|
||||
{"detail": "Engine unhealthy"}
|
||||
```
|
||||
|
||||
You can integrate this into your Docker Compose healthcheck:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jarvis:
|
||||
# ... other config ...
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
```
|
||||
|
||||
## Building Custom Images
|
||||
|
||||
### Adding Extra Dependencies
|
||||
|
||||
To include additional engine backends (such as vLLM or ColBERT memory), modify the install command in the Dockerfile:
|
||||
|
||||
```dockerfile
|
||||
RUN pip install --no-cache-dir uv && \
|
||||
uv pip install --system ".[server,inference-vllm,memory-colbert]"
|
||||
```
|
||||
|
||||
### Overriding the Default Command
|
||||
|
||||
The entrypoint is `jarvis` and the default command is `serve --host 0.0.0.0 --port 8000`. Override the command to change server options:
|
||||
|
||||
```bash
|
||||
docker run -d -p 9000:9000 openjarvis:latest \
|
||||
serve --host 0.0.0.0 --port 9000 --engine ollama --model qwen3:8b
|
||||
```
|
||||
|
||||
Or in Docker Compose:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jarvis:
|
||||
build: .
|
||||
command: ["serve", "--host", "0.0.0.0", "--port", "9000", "--model", "qwen3:8b"]
|
||||
ports:
|
||||
- "9000:9000"
|
||||
```
|
||||
|
||||
### Available CLI Options for `jarvis serve`
|
||||
|
||||
| Option | Description |
|
||||
|----------------------|-----------------------------------------------------|
|
||||
| `--host` | Bind address (default: from config, typically `0.0.0.0`) |
|
||||
| `--port` | Port number (default: from config, typically `8000`) |
|
||||
| `-e` / `--engine` | Engine backend (`ollama`, `vllm`, `llamacpp`, `sglang`) |
|
||||
| `-m` / `--model` | Default model name |
|
||||
| `-a` / `--agent` | Agent for non-streaming requests (`simple`, `orchestrator`, `react`, `openhands`) |
|
||||
|
||||
## Pulling Models
|
||||
|
||||
After starting the Ollama container, you need to pull at least one model before the API server can serve requests:
|
||||
|
||||
```bash
|
||||
docker compose exec ollama ollama pull qwen3:8b
|
||||
```
|
||||
|
||||
Verify models are available through the API:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/v1/models
|
||||
```
|
||||
@@ -0,0 +1,251 @@
|
||||
# launchd Service (macOS)
|
||||
|
||||
OpenJarvis includes a launchd property list (plist) for running the API server as a background service on macOS. This provides automatic startup at login, automatic restart if the process exits, and log capture.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing the service, ensure that OpenJarvis is installed and the `jarvis` command is available at `/usr/local/bin/jarvis`. If you installed via `uv` or `pip` with a different prefix, adjust the path in the plist accordingly.
|
||||
|
||||
```bash
|
||||
pip install 'openjarvis[server]'
|
||||
which jarvis # Verify the installation path
|
||||
```
|
||||
|
||||
Also ensure that an inference engine (such as Ollama) is running and accessible on the machine.
|
||||
|
||||
## Installing the Service
|
||||
|
||||
Copy the plist file to `~/Library/LaunchAgents` and load it:
|
||||
|
||||
```bash
|
||||
cp deploy/launchd/com.openjarvis.plist ~/Library/LaunchAgents/
|
||||
launchctl load ~/Library/LaunchAgents/com.openjarvis.plist
|
||||
```
|
||||
|
||||
The service starts immediately (due to `RunAtLoad`) and will automatically restart at each login.
|
||||
|
||||
Verify it is running:
|
||||
|
||||
```bash
|
||||
launchctl list | grep openjarvis
|
||||
```
|
||||
|
||||
You should see a line with the PID and the label `com.openjarvis`. A `0` in the status column indicates the service is running normally.
|
||||
|
||||
Confirm the server is responding:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
## Plist Reference
|
||||
|
||||
The provided plist file at `deploy/launchd/com.openjarvis.plist`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.openjarvis</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/jarvis</string>
|
||||
<string>serve</string>
|
||||
<string>--host</string>
|
||||
<string>0.0.0.0</string>
|
||||
<string>--port</string>
|
||||
<string>8000</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/openjarvis.stdout.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/openjarvis.stderr.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### Key-by-Key Explanation
|
||||
|
||||
| Key | Value | Description |
|
||||
|----------------------|--------------------------------|------------------------------------------------------------------------------------------------------|
|
||||
| `Label` | `com.openjarvis` | Unique identifier for the service. Used with `launchctl` commands to manage the service. |
|
||||
| `ProgramArguments` | `["/usr/local/bin/jarvis", "serve", "--host", "0.0.0.0", "--port", "8000"]` | The command and arguments to execute. Each element of the command line is a separate string in the array. |
|
||||
| `RunAtLoad` | `true` | Start the service immediately when the plist is loaded (and on each login). |
|
||||
| `KeepAlive` | `true` | Automatically restart the service if it exits for any reason. launchd monitors the process and relaunches it. |
|
||||
| `StandardOutPath` | `/tmp/openjarvis.stdout.log` | File where standard output is written. Contains server startup messages and access logs. |
|
||||
| `StandardErrorPath` | `/tmp/openjarvis.stderr.log` | File where standard error is written. Contains error messages and stack traces. |
|
||||
|
||||
## Viewing Logs
|
||||
|
||||
Server output is written to the two log files specified in the plist:
|
||||
|
||||
```bash
|
||||
# View standard output (startup messages, access logs)
|
||||
cat /tmp/openjarvis.stdout.log
|
||||
|
||||
# View standard error (errors, warnings)
|
||||
cat /tmp/openjarvis.stderr.log
|
||||
|
||||
# Follow logs in real time
|
||||
tail -f /tmp/openjarvis.stdout.log /tmp/openjarvis.stderr.log
|
||||
```
|
||||
|
||||
!!! tip "Persistent log location"
|
||||
Files in `/tmp` may be cleared on reboot. For persistent logs, change the paths in the plist to a permanent location:
|
||||
|
||||
```xml
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/yourname/.openjarvis/openjarvis.stdout.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/yourname/.openjarvis/openjarvis.stderr.log</string>
|
||||
```
|
||||
|
||||
After changing the plist, unload and reload the service for the changes to take effect.
|
||||
|
||||
## Managing the Service
|
||||
|
||||
### Loading and Unloading
|
||||
|
||||
```bash
|
||||
# Load the service (starts it due to RunAtLoad)
|
||||
launchctl load ~/Library/LaunchAgents/com.openjarvis.plist
|
||||
|
||||
# Unload the service (stops it and prevents it from starting at login)
|
||||
launchctl unload ~/Library/LaunchAgents/com.openjarvis.plist
|
||||
```
|
||||
|
||||
### Starting and Stopping
|
||||
|
||||
If the service is loaded but you want to manually stop or start it without unloading:
|
||||
|
||||
```bash
|
||||
# Stop the service
|
||||
launchctl stop com.openjarvis
|
||||
|
||||
# Start the service
|
||||
launchctl start com.openjarvis
|
||||
```
|
||||
|
||||
!!! warning
|
||||
Because `KeepAlive` is set to `true`, using `launchctl stop` will cause launchd to restart the service almost immediately. To fully stop the service, use `launchctl unload` instead.
|
||||
|
||||
### Checking Status
|
||||
|
||||
```bash
|
||||
# List all loaded services matching "openjarvis"
|
||||
launchctl list | grep openjarvis
|
||||
```
|
||||
|
||||
The output columns are:
|
||||
|
||||
| Column | Description |
|
||||
|--------|----------------------------------------------------------------|
|
||||
| PID | Process ID (or `-` if not running) |
|
||||
| Status | Last exit status (`0` = normal) |
|
||||
| Label | The service label (`com.openjarvis`) |
|
||||
|
||||
## Configuration Changes
|
||||
|
||||
### Changing the Port or Host
|
||||
|
||||
Edit the `ProgramArguments` array in the plist. Each argument must be a separate `<string>` element:
|
||||
|
||||
```xml
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/jarvis</string>
|
||||
<string>serve</string>
|
||||
<string>--host</string>
|
||||
<string>127.0.0.1</string>
|
||||
<string>--port</string>
|
||||
<string>9000</string>
|
||||
</array>
|
||||
```
|
||||
|
||||
### Specifying an Engine and Model
|
||||
|
||||
Add additional arguments to the array:
|
||||
|
||||
```xml
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/jarvis</string>
|
||||
<string>serve</string>
|
||||
<string>--host</string>
|
||||
<string>0.0.0.0</string>
|
||||
<string>--port</string>
|
||||
<string>8000</string>
|
||||
<string>--engine</string>
|
||||
<string>ollama</string>
|
||||
<string>--model</string>
|
||||
<string>qwen3:8b</string>
|
||||
</array>
|
||||
```
|
||||
|
||||
### Setting Environment Variables
|
||||
|
||||
Add an `EnvironmentVariables` dictionary to the plist:
|
||||
|
||||
```xml
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>OPENJARVIS_ENGINE_DEFAULT</key>
|
||||
<string>ollama</string>
|
||||
<key>OPENJARVIS_OLLAMA_HOST</key>
|
||||
<string>http://localhost:11434</string>
|
||||
</dict>
|
||||
```
|
||||
|
||||
### Using a Different `jarvis` Binary Path
|
||||
|
||||
If `jarvis` is installed in a virtual environment or a non-standard location, update the first element of `ProgramArguments`:
|
||||
|
||||
```xml
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/yourname/.local/bin/jarvis</string>
|
||||
<string>serve</string>
|
||||
<string>--host</string>
|
||||
<string>0.0.0.0</string>
|
||||
<string>--port</string>
|
||||
<string>8000</string>
|
||||
</array>
|
||||
```
|
||||
|
||||
### Applying Changes
|
||||
|
||||
After editing the plist file, unload and reload the service:
|
||||
|
||||
```bash
|
||||
launchctl unload ~/Library/LaunchAgents/com.openjarvis.plist
|
||||
launchctl load ~/Library/LaunchAgents/com.openjarvis.plist
|
||||
```
|
||||
|
||||
## System-Wide Installation
|
||||
|
||||
The instructions above install the service as a **user agent** (runs only when you are logged in). To run OpenJarvis as a system-wide daemon that starts at boot regardless of user login:
|
||||
|
||||
1. Copy the plist to `/Library/LaunchDaemons/` (requires `sudo`).
|
||||
2. Set the file ownership to `root:wheel`.
|
||||
3. Optionally add a `UserName` key to run as a specific user.
|
||||
|
||||
```bash
|
||||
sudo cp deploy/launchd/com.openjarvis.plist /Library/LaunchDaemons/
|
||||
sudo chown root:wheel /Library/LaunchDaemons/com.openjarvis.plist
|
||||
sudo launchctl load /Library/LaunchDaemons/com.openjarvis.plist
|
||||
```
|
||||
|
||||
!!! note
|
||||
System daemons in `/Library/LaunchDaemons/` run as root by default. Add a `UserName` key to run as a less-privileged user:
|
||||
|
||||
```xml
|
||||
<key>UserName</key>
|
||||
<string>openjarvis</string>
|
||||
```
|
||||
@@ -0,0 +1,242 @@
|
||||
# systemd Service (Linux)
|
||||
|
||||
OpenJarvis includes a systemd unit file for running the API server as a managed background service on Linux. This provides automatic startup on boot, crash recovery, and integration with standard Linux service management tools.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing the service, ensure that:
|
||||
|
||||
1. OpenJarvis is installed in a virtual environment at `/opt/openjarvis/.venv` (or adjust paths accordingly).
|
||||
2. A dedicated `openjarvis` system user exists (recommended for security).
|
||||
3. An inference engine (such as Ollama) is running and accessible.
|
||||
|
||||
Create the user and installation directory:
|
||||
|
||||
```bash
|
||||
sudo useradd --system --create-home --home-dir /opt/openjarvis openjarvis
|
||||
sudo -u openjarvis python3 -m venv /opt/openjarvis/.venv
|
||||
sudo -u openjarvis /opt/openjarvis/.venv/bin/pip install 'openjarvis[server]'
|
||||
```
|
||||
|
||||
## Installing the Service
|
||||
|
||||
Copy the unit file to the systemd directory, reload the daemon, and enable the service:
|
||||
|
||||
```bash
|
||||
sudo cp deploy/systemd/openjarvis.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable openjarvis
|
||||
sudo systemctl start openjarvis
|
||||
```
|
||||
|
||||
Verify it is running:
|
||||
|
||||
```bash
|
||||
sudo systemctl status openjarvis
|
||||
```
|
||||
|
||||
## Service File Reference
|
||||
|
||||
The provided unit file at `deploy/systemd/openjarvis.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=OpenJarvis API Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=openjarvis
|
||||
WorkingDirectory=/opt/openjarvis
|
||||
ExecStart=/opt/openjarvis/.venv/bin/jarvis serve --host 0.0.0.0 --port 8000
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
Environment=HOME=/opt/openjarvis
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### `[Unit]` Section
|
||||
|
||||
| Directive | Value | Description |
|
||||
|---------------|--------------------|-----------------------------------------------------------------------------|
|
||||
| `Description` | `OpenJarvis API Server` | Human-readable name shown in `systemctl status` and logs. |
|
||||
| `After` | `network.target` | Delays startup until the network stack is available, since the server binds to a network socket and may need to reach a remote engine. |
|
||||
|
||||
### `[Service]` Section
|
||||
|
||||
| Directive | Value | Description |
|
||||
|--------------------|--------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
|
||||
| `Type` | `simple` | The process started by `ExecStart` is the main service process. systemd considers the service started immediately. |
|
||||
| `User` | `openjarvis` | Runs the server as the `openjarvis` user rather than root, limiting the blast radius of any security issue. |
|
||||
| `WorkingDirectory` | `/opt/openjarvis` | Sets the working directory for the process. This is where OpenJarvis looks for local files and writes data. |
|
||||
| `ExecStart` | `/opt/openjarvis/.venv/bin/jarvis serve --host 0.0.0.0 --port 8000` | The command to start the server. Uses the full path to the `jarvis` binary inside the virtual environment. |
|
||||
| `Restart` | `on-failure` | Automatically restarts the service if it exits with a non-zero exit code. Does not restart on clean shutdown (`systemctl stop`). |
|
||||
| `RestartSec` | `5` | Waits 5 seconds before attempting a restart, preventing rapid restart loops if the service crashes immediately on startup. |
|
||||
| `Environment` | `HOME=/opt/openjarvis` | Sets the `HOME` environment variable so OpenJarvis finds its configuration at `~/.openjarvis/config.toml` (resolving to `/opt/openjarvis/.openjarvis/config.toml`). |
|
||||
|
||||
### `[Install]` Section
|
||||
|
||||
| Directive | Value | Description |
|
||||
|--------------|---------------------|---------------------------------------------------------------------------------------------|
|
||||
| `WantedBy` | `multi-user.target` | The service starts when the system reaches multi-user mode (standard boot target for servers). `systemctl enable` creates a symlink under this target. |
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Changing the Bind Address and Port
|
||||
|
||||
Edit the `ExecStart` line to change the host or port:
|
||||
|
||||
```ini
|
||||
ExecStart=/opt/openjarvis/.venv/bin/jarvis serve --host 127.0.0.1 --port 9000
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Binding to `127.0.0.1` restricts access to localhost only. Use this when running behind a reverse proxy like Nginx or Caddy.
|
||||
|
||||
### Setting the Engine and Model
|
||||
|
||||
Pass additional flags to `jarvis serve`:
|
||||
|
||||
```ini
|
||||
ExecStart=/opt/openjarvis/.venv/bin/jarvis serve --host 0.0.0.0 --port 8000 --engine ollama --model qwen3:8b
|
||||
```
|
||||
|
||||
### Adding Environment Variables
|
||||
|
||||
Add multiple `Environment` directives or use `EnvironmentFile` for complex configurations:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
Environment=HOME=/opt/openjarvis
|
||||
Environment=OPENJARVIS_ENGINE_DEFAULT=vllm
|
||||
Environment=OPENJARVIS_OLLAMA_HOST=http://localhost:11434
|
||||
```
|
||||
|
||||
Or load from a file:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
EnvironmentFile=/opt/openjarvis/.env
|
||||
```
|
||||
|
||||
### Changing the User
|
||||
|
||||
If you prefer a different service user, update both the `User` directive and the paths:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
User=myuser
|
||||
WorkingDirectory=/home/myuser/openjarvis
|
||||
ExecStart=/home/myuser/openjarvis/.venv/bin/jarvis serve --host 0.0.0.0 --port 8000
|
||||
Environment=HOME=/home/myuser/openjarvis
|
||||
```
|
||||
|
||||
### Using a Configuration File
|
||||
|
||||
Ensure the configuration file exists at the path where `HOME` points:
|
||||
|
||||
```bash
|
||||
sudo -u openjarvis mkdir -p /opt/openjarvis/.openjarvis
|
||||
sudo -u openjarvis cp config.toml /opt/openjarvis/.openjarvis/config.toml
|
||||
```
|
||||
|
||||
The server reads `~/.openjarvis/config.toml` on startup, where `~` resolves from the `HOME` environment variable.
|
||||
|
||||
## Viewing Logs
|
||||
|
||||
OpenJarvis logs are captured by journald. View them with `journalctl`:
|
||||
|
||||
```bash
|
||||
# View all logs for the service
|
||||
sudo journalctl -u openjarvis
|
||||
|
||||
# Follow logs in real time
|
||||
sudo journalctl -u openjarvis -f
|
||||
|
||||
# View logs since the last boot
|
||||
sudo journalctl -u openjarvis -b
|
||||
|
||||
# View logs from the last hour
|
||||
sudo journalctl -u openjarvis --since "1 hour ago"
|
||||
|
||||
# View only error-level messages
|
||||
sudo journalctl -u openjarvis -p err
|
||||
```
|
||||
|
||||
## Managing the Service
|
||||
|
||||
### Start, Stop, and Restart
|
||||
|
||||
```bash
|
||||
# Start the service
|
||||
sudo systemctl start openjarvis
|
||||
|
||||
# Stop the service
|
||||
sudo systemctl stop openjarvis
|
||||
|
||||
# Restart the service (stop + start)
|
||||
sudo systemctl restart openjarvis
|
||||
|
||||
# Reload configuration without full restart (sends SIGHUP)
|
||||
sudo systemctl reload-or-restart openjarvis
|
||||
```
|
||||
|
||||
### Check Status
|
||||
|
||||
```bash
|
||||
sudo systemctl status openjarvis
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
● openjarvis.service - OpenJarvis API Server
|
||||
Loaded: loaded (/etc/systemd/system/openjarvis.service; enabled; preset: enabled)
|
||||
Active: active (running) since Fri 2026-02-21 10:00:00 UTC; 2h ago
|
||||
Main PID: 12345 (jarvis)
|
||||
Tasks: 4 (limit: 4915)
|
||||
Memory: 256.0M
|
||||
CPU: 1min 23s
|
||||
CGroup: /system.slice/openjarvis.service
|
||||
└─12345 /opt/openjarvis/.venv/bin/python /opt/openjarvis/.venv/bin/jarvis serve --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### Enable and Disable on Boot
|
||||
|
||||
```bash
|
||||
# Enable automatic start on boot
|
||||
sudo systemctl enable openjarvis
|
||||
|
||||
# Disable automatic start on boot
|
||||
sudo systemctl disable openjarvis
|
||||
```
|
||||
|
||||
### Apply Changes After Editing the Unit File
|
||||
|
||||
After modifying `/etc/systemd/system/openjarvis.service`, reload the systemd daemon and restart the service:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart openjarvis
|
||||
```
|
||||
|
||||
## Running Alongside Ollama
|
||||
|
||||
If Ollama is also managed via systemd, you can add an ordering dependency so the OpenJarvis service waits for Ollama to start:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=OpenJarvis API Server
|
||||
After=network.target ollama.service
|
||||
Requires=ollama.service
|
||||
```
|
||||
|
||||
| Directive | Description |
|
||||
|------------|--------------------------------------------------------------------------|
|
||||
| `After` | Ensures OpenJarvis starts after Ollama. |
|
||||
| `Requires` | If Ollama fails to start, OpenJarvis will not start either. |
|
||||
|
||||
!!! note
|
||||
Use `Wants` instead of `Requires` if you want OpenJarvis to start even when Ollama is unavailable (for example, if you plan to start Ollama manually later).
|
||||
Reference in New Issue
Block a user