refactor(ansible): rename freecad_mcp env vars and rework deployment
- Drop `FREECAD_MCP_` prefix from env vars (use `FREECAD_*`) - Update freecad_mcp port from 22032 to 22061 - Document that FreeCAD bridge is required for tool calls - Replace kottos deployment with pallas deployment
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
# Kottos runtime environment — rendered by Ansible from inventory host_vars.
|
||||
# ------------------------------------------------------------------------
|
||||
# Loaded by systemd (EnvironmentFile=) and inherited by the pallas process.
|
||||
# ``.env`` vars NOT set here come from pallas.server's defaults — tweak by
|
||||
# adding the variable to host_vars and this template, not by editing the
|
||||
# rendered file on the host.
|
||||
|
||||
# ── Logging ─────────────────────────────────────────────────────────────────
|
||||
# Stdout JSON is the preferred sink for systemd+journald+Alloy deployments.
|
||||
# Rotating file sink is disabled by pointing PALLAS_LOG_FILE at /dev/null so
|
||||
# we don't write every record twice.
|
||||
PALLAS_LOG_STDOUT=1
|
||||
PALLAS_LOG_FILE=/dev/null
|
||||
PALLAS_LOG_LEVEL={{ pallas_log_level | default('INFO') }}
|
||||
|
||||
# ── Config location ─────────────────────────────────────────────────────────
|
||||
# PALLAS_AGENTS_CONFIG can be overridden to point at a non-default topology
|
||||
# (e.g. staging scenarios). Default: agents.yaml next to the working dir.
|
||||
PALLAS_AGENTS_CONFIG={{ kottos_directory }}/agents.yaml
|
||||
|
||||
# ── LLM provider / MCP server secrets ───────────────────────────────────────
|
||||
# Secrets are rendered into fastagent.secrets.yaml rather than env vars so
|
||||
# fast-agent's existing YAML-merge logic applies. This block stays empty
|
||||
# intentionally — the template exists for future per-host tunables.
|
||||
@@ -1,43 +1,62 @@
|
||||
# Kottos — Deployment Configuration (rendered by Ansible)
|
||||
# ------------------------------------------------------------------
|
||||
# Single source of truth for agent topology, ports, and registry
|
||||
# metadata. Read by Pallas at startup. The kottos/agents.yaml
|
||||
# committed in the kottos repo is the local-dev equivalent; Ansible
|
||||
# overwrites it with this rendered version.
|
||||
#
|
||||
# Host + namespace + registry port come from inventory host_vars so
|
||||
# Ouranos / Virgo / Taurus each get their own shape without template
|
||||
# edits.
|
||||
# Kottos — Deployment Configuration
|
||||
# Single source of truth for agent topology, ports, and registry metadata.
|
||||
# Read by Pallas at startup.
|
||||
|
||||
name: kottos
|
||||
version: "1.0.0"
|
||||
host: {{ kottos_agents_host | default(kottos_host) | default(inventory_hostname) }}
|
||||
namespace: {{ kottos_namespace | default('ca.helu.kottos') }}
|
||||
registry_port: {{ kottos_registry_port | default(24100) }}
|
||||
host: {{ kottos_bind_host | default(inventory_hostname) }}
|
||||
namespace: ca.helu.kottos
|
||||
registry_port: {{ kottos_registry_port }}
|
||||
|
||||
agents:
|
||||
harper:
|
||||
module: agents.harper
|
||||
port: {{ kottos_harper_port | default(24101) }}
|
||||
port: 24101
|
||||
title: Harper
|
||||
description: "Scrappy engineer — rapid prototyping, hacking, and creative problem-solving"
|
||||
depends_on: [research, tech_research]
|
||||
{% if kottos_harper_model is defined %}
|
||||
model: {{ kottos_harper_model }}
|
||||
{% endif %}
|
||||
|
||||
scotty:
|
||||
module: agents.scotty
|
||||
port: {{ kottos_scotty_port | default(24102) }}
|
||||
port: 24102
|
||||
title: Scotty
|
||||
description: "Systems administration expert — infrastructure diagnostics, security hardening, and keeping everything running"
|
||||
depends_on: [tech_research]
|
||||
{% if kottos_scotty_model is defined %}
|
||||
model: {{ kottos_scotty_model }}
|
||||
{% endif %}
|
||||
|
||||
research:
|
||||
module: agents.research
|
||||
port: {{ kottos_research_port | default(24150) }}
|
||||
port: 24150
|
||||
title: Research Agent
|
||||
description: "Web search via Argos and knowledge graph via Neo4j"
|
||||
{% if kottos_research_model is defined %}
|
||||
model: {{ kottos_research_model }}
|
||||
model_capabilities:
|
||||
vision: {{ kottos_research_model_vision | default(true) }}
|
||||
context_window: {{ kottos_research_model_context_window | default(16384) }}
|
||||
max_output_tokens: {{ kottos_research_model_max_output_tokens | default(8192) }}
|
||||
{% endif %}
|
||||
|
||||
tech_research:
|
||||
module: agents.tech_research
|
||||
port: {{ kottos_tech_research_port | default(24151) }}
|
||||
port: 24151
|
||||
title: Tech Research
|
||||
description: "Technical investigation — library comparisons, API docs, framework patterns, code examples"
|
||||
{% if kottos_tech_research_model is defined %}
|
||||
model: {{ kottos_tech_research_model }}
|
||||
{% endif %}
|
||||
|
||||
case:
|
||||
module: agents.case
|
||||
port: 24152
|
||||
title: CASE
|
||||
description: "Field systems agent — SD card imaging, LAN scanning, and storage operations on korax.helu.ca"
|
||||
depends_on: []
|
||||
{% if kottos_case_model is defined %}
|
||||
model: {{ kottos_case_model }}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
---
|
||||
- name: Deploy Kottos (Pallas FastAgent runtime)
|
||||
- name: Deploy Kottos AI Agent Platform
|
||||
hosts: ubuntu
|
||||
vars:
|
||||
ansible_common_remote_group: "{{ kottos_group | default([]) }}"
|
||||
allow_world_readable_tmpfiles: true
|
||||
|
||||
handlers:
|
||||
- name: restart kottos
|
||||
become: true
|
||||
ansible.builtin.systemd:
|
||||
name: kottos
|
||||
state: restarted
|
||||
|
||||
tasks:
|
||||
- name: Check if host has kottos service
|
||||
ansible.builtin.set_fact:
|
||||
@@ -14,51 +21,84 @@
|
||||
ansible.builtin.meta: end_host
|
||||
when: not has_kottos_service
|
||||
|
||||
- name: Install required packages
|
||||
become: true
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- acl
|
||||
- npm
|
||||
- curl
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Create Kottos group
|
||||
become: true
|
||||
ansible.builtin.group:
|
||||
name: "{{ kottos_group }}"
|
||||
state: present
|
||||
|
||||
- name: Create kottos user
|
||||
- name: Create Kottos user
|
||||
become: true
|
||||
ansible.builtin.user:
|
||||
name: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
home: "/home/{{ kottos_user }}"
|
||||
home: "{{ kottos_directory }}"
|
||||
shell: /bin/bash
|
||||
system: false
|
||||
create_home: true
|
||||
system: true
|
||||
create_home: false
|
||||
|
||||
- name: Add keeper_user to kottos group (optional — enables passwordless tailing)
|
||||
- name: Add keeper_user to kottos group
|
||||
become: true
|
||||
ansible.builtin.user:
|
||||
name: "{{ keeper_user }}"
|
||||
groups: "{{ kottos_group }}"
|
||||
append: true
|
||||
when: keeper_user is defined
|
||||
|
||||
- name: Add kottos user to docker group
|
||||
become: true
|
||||
ansible.builtin.user:
|
||||
name: "{{ kottos_user }}"
|
||||
groups: docker
|
||||
append: true
|
||||
notify: restart kottos
|
||||
|
||||
- name: Reset connection to pick up new group membership
|
||||
ansible.builtin.meta: reset_connection
|
||||
|
||||
- name: Create Kottos install directory
|
||||
- name: Create Kottos directory
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ kottos_directory }}"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
state: directory
|
||||
mode: '0750'
|
||||
mode: '750'
|
||||
|
||||
- name: Ensure base packages for Python + Docker MCP workflows
|
||||
- name: Create vendored Pallas directory
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ kottos_directory }}/vendor/pallas"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
state: directory
|
||||
mode: '750'
|
||||
|
||||
- name: Ensure tar is installed for unarchive task
|
||||
become: true
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- tar
|
||||
- python3
|
||||
- python3-venv
|
||||
- python3-dev
|
||||
- git
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Ensure Python 3.13, venv, dev headers, and ACL are installed
|
||||
become: true
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- python3.13
|
||||
- python3.13-venv
|
||||
- python3.13-dev
|
||||
- acl
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
@@ -69,43 +109,52 @@
|
||||
dest: "{{ kottos_directory }}"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
mode: '0550'
|
||||
mode: '550'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Ensure .venv directory ownership is correct
|
||||
- name: Transfer and unarchive vendored Pallas source
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ kottos_directory }}/.venv"
|
||||
ansible.builtin.unarchive:
|
||||
src: "~/rel/pallas_{{ pallas_rel }}.tar"
|
||||
dest: "{{ kottos_directory }}/vendor/pallas"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
state: directory
|
||||
recurse: true
|
||||
when: ansible_facts['file'] is defined or true
|
||||
mode: '550'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Create virtual environment for Kottos
|
||||
- name: Rewrite pallas-mcp dependency to use vendored local path
|
||||
become: true
|
||||
ansible.builtin.replace:
|
||||
path: "{{ kottos_directory }}/pyproject.toml"
|
||||
regexp: '"pallas-mcp @ git\+ssh://[^"]+"'
|
||||
replace: '"pallas-mcp @ file://{{ kottos_directory }}/vendor/pallas"'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Create virtual environment for Kottos (Python 3.13)
|
||||
become: true
|
||||
become_user: "{{ kottos_user }}"
|
||||
ansible.builtin.command:
|
||||
cmd: "python3 -m venv {{ kottos_directory }}/.venv/"
|
||||
cmd: "python3.13 -m venv {{ kottos_directory }}/.venv/"
|
||||
creates: "{{ kottos_directory }}/.venv/bin/activate"
|
||||
|
||||
- name: Install wheel in the virtualenv
|
||||
- name: Install wheel and mcp-server-time in virtualenv
|
||||
become: true
|
||||
become_user: "{{ kottos_user }}"
|
||||
ansible.builtin.pip:
|
||||
name:
|
||||
- wheel
|
||||
- mcp-server-time
|
||||
state: latest
|
||||
virtualenv: "{{ kottos_directory }}/.venv"
|
||||
|
||||
- name: Install Kottos (pyproject.toml — pulls in pallas-mcp and fast-agent-mcp)
|
||||
- name: Install Kottos (and its rewritten local pallas-mcp) in virtualenv
|
||||
become: true
|
||||
become_user: "{{ kottos_user }}"
|
||||
ansible.builtin.pip:
|
||||
chdir: "{{ kottos_directory }}/kottos"
|
||||
chdir: "{{ kottos_directory }}"
|
||||
name: .
|
||||
virtualenv: "{{ kottos_directory }}/.venv"
|
||||
virtualenv_command: python3 -m venv
|
||||
virtualenv_command: python3.13 -m venv
|
||||
notify: restart kottos
|
||||
|
||||
- name: Template agents.yaml
|
||||
@@ -115,7 +164,7 @@
|
||||
dest: "{{ kottos_directory }}/agents.yaml"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
mode: '0640'
|
||||
mode: '640'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Template fastagent.config.yaml
|
||||
@@ -125,38 +174,27 @@
|
||||
dest: "{{ kottos_directory }}/fastagent.config.yaml"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
mode: '0640'
|
||||
mode: '640'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Template fastagent.secrets.yaml (vault-rendered)
|
||||
- name: Template fastagent.secrets.yaml
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: fastagent.secrets.yaml.j2
|
||||
dest: "{{ kottos_directory }}/fastagent.secrets.yaml"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
mode: '0600'
|
||||
notify: restart kottos
|
||||
no_log: true
|
||||
|
||||
- name: Template runtime .env (PALLAS_LOG_STDOUT etc.)
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: .env.j2
|
||||
dest: "{{ kottos_directory }}/.env"
|
||||
owner: "{{ kottos_user }}"
|
||||
group: "{{ kottos_group }}"
|
||||
mode: '0640'
|
||||
mode: '640'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Template systemd unit
|
||||
- name: Template systemd service file
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: kottos.service.j2
|
||||
dest: /etc/systemd/system/kottos.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
mode: '644'
|
||||
notify: restart kottos
|
||||
|
||||
- name: Enable and start kottos service
|
||||
@@ -167,26 +205,15 @@
|
||||
state: started
|
||||
daemon_reload: true
|
||||
|
||||
- name: Flush handlers before validation probes
|
||||
- name: Flush handlers to restart service before validation
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
# ── Validation ──────────────────────────────────────────────────────────
|
||||
# Registry is the only endpoint that responds with a deterministic JSON
|
||||
# payload without requiring an MCP session, so we probe it. Agent ports
|
||||
# are exercised by Daedalus's health-poll loop once registered.
|
||||
- name: Validate Kottos registry responds
|
||||
- name: Validate Kottos registry liveness
|
||||
ansible.builtin.uri:
|
||||
url: "http://localhost:{{ kottos_registry_port | default(24100) }}/.well-known/mcp/server.json"
|
||||
url: "http://localhost:{{ kottos_registry_port }}/live"
|
||||
status_code: 200
|
||||
return_content: true
|
||||
register: registry_check
|
||||
register: kottos_live
|
||||
retries: 10
|
||||
delay: 3
|
||||
until: registry_check.status == 200
|
||||
|
||||
handlers:
|
||||
- name: restart kottos
|
||||
become: true
|
||||
ansible.builtin.systemd:
|
||||
name: kottos
|
||||
state: restarted
|
||||
delay: 5
|
||||
until: kottos_live.status == 200
|
||||
|
||||
@@ -1,66 +1,64 @@
|
||||
# Kottos — fast-agent configuration (rendered by Ansible)
|
||||
# ------------------------------------------------------------------
|
||||
# Committed-to-kottos copy is the local-dev equivalent; Ansible overwrites
|
||||
# it with this rendered file on deploy. MCP server URLs are parametrised
|
||||
# so the same template renders correctly for Ouranos (.incus) and Virgo
|
||||
# (.virgo / .taurus) — each environment's host_vars supplies the base URLs.
|
||||
# Kottos — Configuration
|
||||
# LLM provider and MCP server settings.
|
||||
# Secrets (api_key, tokens) live in fastagent.secrets.yaml (gitignored)
|
||||
#
|
||||
# This template is intended to be byte-identical between environments
|
||||
# (Virgo dev, Taurus prod). All environment-specific values come from
|
||||
# host_vars or group_vars/all/vars.yml. Do NOT introduce environment-
|
||||
# specific literals here.
|
||||
|
||||
default_model: {{ kottos_default_model | default('openai.Qwen3.5-35B-A3B-UD-Q4_K_XL.gguf') }}
|
||||
# Default Model Definition
|
||||
default_model: {{ kottos_default_model }}
|
||||
|
||||
# ── Model Capabilities ──────────────────────────────────────────────────────
|
||||
# Declares capabilities for models not in fast-agent's ModelDatabase.
|
||||
# vision: true adds image/jpeg, image/png, image/webp to the tokenizer list.
|
||||
model_capabilities:
|
||||
vision: {{ kottos_model_vision | default(true) | string | lower }}
|
||||
context_window: {{ kottos_model_context_window | default(192000) }}
|
||||
max_output_tokens: {{ kottos_model_max_output_tokens | default(16384) }}
|
||||
vision: {{ kottos_model_vision }}
|
||||
context_window: {{ kottos_model_context_window }}
|
||||
max_output_tokens: {{ kottos_model_max_output_tokens }}
|
||||
|
||||
# ── LLM Providers ───────────────────────────────────────────────────────────
|
||||
# LLM Providers
|
||||
anthropic:
|
||||
base_url: {{ kottos_anthropic_base_url }}
|
||||
generic:
|
||||
base_url: {{ kottos_generic_base_url }}
|
||||
openai:
|
||||
base_url: {{ kottos_openai_base_url | default('http://nyx.helu.ca:22079/v1') }}
|
||||
base_url: {{ kottos_openai_base_url }}
|
||||
|
||||
# MCP Servers — alphabetical to match the dev sample (kottos/fastagent.config.yaml)
|
||||
mcp:
|
||||
servers:
|
||||
# ── Web search via SearXNG (argos) ───────────────────────────────────────
|
||||
argos:
|
||||
transport: http
|
||||
url: "{{ kottos_argos_url | default('http://miranda.incus:25534/mcp') }}"
|
||||
|
||||
# ── Knowledge graph — Neo4j ──────────────────────────────────────────────
|
||||
neo4j_cypher:
|
||||
transport: http
|
||||
url: "{{ kottos_neo4j_cypher_url | default('http://circe.helu.ca:22034/mcp') }}"
|
||||
|
||||
# ── Shell + file operations — Kernos (Caliban) ───────────────────────────
|
||||
kernos_scotty:
|
||||
transport: http
|
||||
url: "{{ kottos_kernos_scotty_url | default('http://caliban.incus:22062/mcp') }}"
|
||||
load_on_start: false
|
||||
|
||||
# ── Agent S computer automation — Rommie on Caliban ──────────────────────
|
||||
rommie:
|
||||
transport: http
|
||||
url: "{{ kottos_rommie_url | default('http://caliban.incus:20361/mcp') }}"
|
||||
load_on_start: false
|
||||
|
||||
# ── Git repository management — Gitea MCP ────────────────────────────────
|
||||
gitea:
|
||||
transport: http
|
||||
url: "{{ kottos_gitea_url | default('http://miranda.incus:25535/mcp') }}"
|
||||
|
||||
# ── Grafana observability ───────────────────────────────────────────────
|
||||
grafana:
|
||||
transport: http
|
||||
url: "{{ kottos_grafana_url | default('http://miranda.incus:25533/mcp') }}"
|
||||
|
||||
# ── Shell + file operations — Kernos (Korax) ─────────────────────────────
|
||||
## Andromeda Shell & File Operations — Kernos for Harper
|
||||
### Auth header provided by fastagent.secrets.yaml (per-agent Kernos token)
|
||||
andromeda:
|
||||
transport: http
|
||||
url: "{{ kottos_kernos_harper_url | default('http://caliban.helu.ca:20261/mcp') }}"
|
||||
load_on_start: false
|
||||
url: "{{ kottos_andromeda_mcp_url }}"
|
||||
|
||||
# ── GitHub MCP Server (local Docker, stdio) ──────────────────────────────
|
||||
# GITHUB_PERSONAL_ACCESS_TOKEN provided by fastagent.secrets.yaml
|
||||
## Argos Web Search & Page Fetch
|
||||
### No Auth
|
||||
argos:
|
||||
transport: http
|
||||
url: "{{ kottos_argos_mcp_url }}"
|
||||
|
||||
## Argus Shell & File Operations — Kernos for Scotty
|
||||
### Auth header provided by fastagent.secrets.yaml (per-agent Kernos token)
|
||||
argus:
|
||||
transport: http
|
||||
url: "{{ kottos_argus_mcp_url }}"
|
||||
|
||||
## Context7 Library/framework documentation (local stdio)
|
||||
context7:
|
||||
command: "npx"
|
||||
args: ["-y", "@upstash/context7-mcp"]
|
||||
|
||||
## Gitea Git Repository Management
|
||||
### No client auth (server-side auth only)
|
||||
gitea:
|
||||
transport: http
|
||||
url: "{{ kottos_gitea_mcp_url }}"
|
||||
|
||||
## GitHub MCP Server (local Docker, stdio)
|
||||
### GITHUB_PERSONAL_ACCESS_TOKEN provided by fastagent.secrets.yaml
|
||||
github:
|
||||
command: "docker"
|
||||
args:
|
||||
@@ -71,38 +69,57 @@ mcp:
|
||||
- "GITHUB_PERSONAL_ACCESS_TOKEN"
|
||||
- "ghcr.io/github/github-mcp-server"
|
||||
|
||||
# ── Library/framework documentation — Context7 (local stdio) ─────────────
|
||||
context7:
|
||||
command: "npx"
|
||||
args: ["-y", "@upstash/context7-mcp"]
|
||||
## Grafana Observability
|
||||
### No Auth
|
||||
grafana:
|
||||
transport: http
|
||||
url: "{{ kottos_grafana_mcp_url }}"
|
||||
|
||||
# ── Current time and timezone (local stdio) ──────────────────────────────
|
||||
time:
|
||||
command: "mcp-server-time"
|
||||
args: ["--local-timezone={{ kottos_timezone | default('America/Toronto') }}"]
|
||||
## Korax Shell & File Operations — Kernos for CASE
|
||||
### Auth header provided by fastagent.secrets.yaml (per-agent Kernos token)
|
||||
korax:
|
||||
transport: http
|
||||
url: "{{ kottos_korax_mcp_url }}"
|
||||
load_on_start: false
|
||||
|
||||
# ── Mnemosyne knowledge search — workspace-scoped ────────────────────────
|
||||
# Auth is a long-lived team JWT supplied by fastagent.secrets.yaml
|
||||
# (forward_inbound_auth=false — Mnemosyne validates the team JWT).
|
||||
## Mnemosyne Knowledge Library — workspace-scoped
|
||||
### Auth is a long-lived team JWT rendered into fastagent.secrets.yaml from
|
||||
### the OCI Vault entry {env}-mnemosyne-kottos-token.
|
||||
mnemosyne:
|
||||
transport: http
|
||||
url: "{{ kottos_mnemosyne_url | default('https://mnemosyne.ouranos.helu.ca/mcp/') }}"
|
||||
url: "{{ kottos_mnemosyne_mcp_url }}"
|
||||
|
||||
# ── Kottos internal sub-agents ───────────────────────────────────────────
|
||||
# These stay on localhost regardless of environment — Pallas serves the
|
||||
# sub-agents on the same host as the top-level agents.
|
||||
## Neo4j Cypher Memory Graph
|
||||
neo4j_cypher:
|
||||
transport: http
|
||||
url: "{{ kottos_neo4j_mcp_url }}"
|
||||
|
||||
## Kottos internal sub-agents
|
||||
### Research (Web, Knowledge)
|
||||
research:
|
||||
transport: http
|
||||
url: "http://localhost:{{ kottos_research_port | default(24150) }}/mcp"
|
||||
url: "{{ kottos_research_mcp_url }}"
|
||||
|
||||
## Rommie Agent S Computer Use Agent
|
||||
rommie:
|
||||
transport: http
|
||||
url: "{{ kottos_rommie_mcp_url }}"
|
||||
load_on_start: false
|
||||
|
||||
### Research (Web, Context7)
|
||||
tech_research:
|
||||
transport: http
|
||||
url: "http://localhost:{{ kottos_tech_research_port | default(24151) }}/mcp"
|
||||
url: "{{ kottos_tech_research_mcp_url }}"
|
||||
|
||||
## Current time and time calculator (local stdio)
|
||||
time:
|
||||
command: "{{ kottos_directory }}/.venv/bin/mcp-server-time"
|
||||
args: ["--local-timezone={{ kottos_timezone | default('America/Toronto') }}"]
|
||||
|
||||
logger:
|
||||
type: none
|
||||
level: {{ kottos_fastagent_log_level | default('info') }}
|
||||
progress_display: false
|
||||
show_chat: false
|
||||
show_tools: false
|
||||
type: console
|
||||
level: info
|
||||
progress_display: true
|
||||
show_chat: true
|
||||
show_tools: true
|
||||
truncate_tools: true
|
||||
|
||||
@@ -1,27 +1,35 @@
|
||||
# Kottos — fast-agent secrets (rendered by Ansible from the vault)
|
||||
# ------------------------------------------------------------------
|
||||
# Never commit the rendered file. Each value here pulls from a vault
|
||||
# variable — if a vault variable is missing, Ansible will fail the
|
||||
# template step with a clear error before the file is written.
|
||||
#
|
||||
# Same structure as fastagent.config.yaml; values merge with secrets
|
||||
# taking precedence (fast-agent deep-merges the two).
|
||||
# Kottos — Secrets
|
||||
# Managed by Ansible. Values fetched from OCI Vault at deploy time.
|
||||
# Merges with fastagent.config.yaml (secrets take precedence).
|
||||
|
||||
openai:
|
||||
api_key: "{{ vault_kottos_openai_api_key }}"
|
||||
api_key: "{{ kottos_openai_api_key }}"
|
||||
|
||||
anthropic:
|
||||
api_key: "{{ kottos_anthropic_api_key }}"
|
||||
|
||||
mcp:
|
||||
servers:
|
||||
github:
|
||||
env:
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: "{{ vault_kottos_github_pat }}"
|
||||
|
||||
angelia:
|
||||
# Per-agent Kernos MCP bearer tokens so Kernos can distinguish callers.
|
||||
# Kottos itself does not consume these — they are surfaced to each agent
|
||||
# module via fast-agent's server auth headers below.
|
||||
argus:
|
||||
headers:
|
||||
Authorization: "Bearer {{ vault_kottos_angelia_bearer }}"
|
||||
Authorization: "Bearer {{ scotty_kernos_mcp_token }}"
|
||||
andromeda:
|
||||
headers:
|
||||
Authorization: "Bearer {{ harper_kernos_mcp_token }}"
|
||||
korax:
|
||||
headers:
|
||||
Authorization: "Bearer {{ case_kernos_mcp_token }}"
|
||||
|
||||
# Long-lived team JWT minted in Daedalus admin UI.
|
||||
# See kottos/README.md § "Mnemosyne memory" for the rotation procedure.
|
||||
# Downstream MCP bearer tokens
|
||||
arke:
|
||||
headers:
|
||||
Authorization: "Bearer {{ kottos_arke_mcp_token }}"
|
||||
mnemosyne:
|
||||
headers:
|
||||
Authorization: "Bearer {{ vault_kottos_mnemosyne_jwt }}"
|
||||
Authorization: "Bearer {{ mnemosyne_kottos_token }}"
|
||||
github:
|
||||
env:
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: "{{ kottos_github_pa_token }}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Kottos — Pallas FastAgent runtime ({{ kottos_host | default(inventory_hostname) }})
|
||||
After=network.target
|
||||
Description=Kottos AI Agent Platform
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
@@ -8,26 +8,17 @@ Type=simple
|
||||
User={{ kottos_user }}
|
||||
Group={{ kottos_group }}
|
||||
WorkingDirectory={{ kottos_directory }}
|
||||
EnvironmentFile={{ kottos_directory }}/.env
|
||||
Environment="PATH={{ kottos_directory }}/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
ExecStart={{ kottos_directory }}/.venv/bin/pallas
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
RestartSec=10
|
||||
|
||||
# Journal is the durable sink (Alloy picks up via loki.source.journal and
|
||||
# relabels SyslogIdentifier=kottos into {service="pallas", project="kottos"}
|
||||
# for Loki). Stdout from pallas is already JSON thanks to
|
||||
# PALLAS_LOG_STDOUT=1 set in the .env file.
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=kottos
|
||||
|
||||
# Pallas needs to reach localhost sibling agents + upstream MCP servers
|
||||
# and read its own .venv / agents.yaml / config files. No hardening flags
|
||||
# that would block those paths.
|
||||
NoNewPrivileges=false
|
||||
ProtectSystem=false
|
||||
ProtectHome=false
|
||||
PrivateTmp=false
|
||||
# Security hardening
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths={{ kottos_directory }}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
34
ansible/kottos/remove.yml
Normal file
34
ansible/kottos/remove.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
- name: Remove Kottos AI Agent Platform
|
||||
hosts: ubuntu
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Check if host has kottos service
|
||||
ansible.builtin.set_fact:
|
||||
has_kottos_service: "{{ 'kottos' in services | default([]) }}"
|
||||
|
||||
- name: Skip hosts without kottos service
|
||||
ansible.builtin.meta: end_host
|
||||
when: not has_kottos_service
|
||||
|
||||
- name: Stop and disable kottos service
|
||||
ansible.builtin.systemd:
|
||||
name: kottos
|
||||
state: stopped
|
||||
enabled: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove systemd service file
|
||||
ansible.builtin.file:
|
||||
path: /etc/systemd/system/kottos.service
|
||||
state: absent
|
||||
|
||||
- name: Reload systemd daemon
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: Remove Kottos directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ kottos_directory }}"
|
||||
state: absent
|
||||
@@ -1,48 +1,84 @@
|
||||
- name: Stage Kottos release tarball
|
||||
---
|
||||
- name: Stage Kottos and Pallas release tarballs
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
archive_path: "{{rel_dir}}/kottos_{{kottos_rel}}.tar"
|
||||
kottos_archive_path: "{{ rel_dir }}/kottos_{{ kottos_rel }}.tar"
|
||||
kottos_repo_url: "ssh://git@git.helu.ca:22022/r/kottos.git"
|
||||
kottos_repo_dir: "{{repo_dir}}/kottos"
|
||||
kottos_repo_dir: "{{ repo_dir }}/kottos"
|
||||
pallas_archive_path: "{{ rel_dir }}/pallas_{{ pallas_rel }}.tar"
|
||||
pallas_repo_url: "ssh://git@git.helu.ca:22022/r/pallas.git"
|
||||
pallas_repo_dir: "{{ repo_dir }}/pallas"
|
||||
|
||||
tasks:
|
||||
- name: Ensure release directory exists
|
||||
file:
|
||||
path: "{{rel_dir}}"
|
||||
ansible.builtin.file:
|
||||
path: "{{ rel_dir }}"
|
||||
state: directory
|
||||
mode: '755'
|
||||
|
||||
- name: Ensure repo directory exists
|
||||
file:
|
||||
path: "{{repo_dir}}"
|
||||
ansible.builtin.file:
|
||||
path: "{{ repo_dir }}"
|
||||
state: directory
|
||||
mode: '755'
|
||||
|
||||
# --- Kottos ------------------------------------------------------------
|
||||
- name: Clone Kottos repository if not present
|
||||
ansible.builtin.git:
|
||||
repo: "{{kottos_repo_url}}"
|
||||
dest: "{{kottos_repo_dir}}"
|
||||
version: "{{kottos_rel}}"
|
||||
repo: "{{ kottos_repo_url }}"
|
||||
dest: "{{ kottos_repo_dir }}"
|
||||
version: "{{ kottos_rel }}"
|
||||
accept_hostkey: true
|
||||
register: git_clone
|
||||
register: kottos_clone
|
||||
ignore_errors: true
|
||||
|
||||
- name: Fetch latest changes if already cloned
|
||||
ansible.builtin.git:
|
||||
repo: "{{kottos_repo_url}}"
|
||||
dest: "{{kottos_repo_dir}}"
|
||||
version: "{{kottos_rel}}"
|
||||
update: true
|
||||
force: true
|
||||
- name: Fetch all remote branches and tags (kottos)
|
||||
ansible.builtin.command: git fetch --all
|
||||
args:
|
||||
chdir: "{{ kottos_repo_dir }}"
|
||||
when: kottos_clone is not changed
|
||||
changed_when: false
|
||||
|
||||
- name: Create release archive
|
||||
ansible.builtin.archive:
|
||||
path: "{{kottos_repo_dir}}"
|
||||
dest: "{{archive_path}}"
|
||||
format: tar
|
||||
exclude_path:
|
||||
- "{{kottos_repo_dir}}/.git"
|
||||
- "{{kottos_repo_dir}}/.venv"
|
||||
- "{{kottos_repo_dir}}/__pycache__"
|
||||
- "{{kottos_repo_dir}}/fastagent.secrets.yaml"
|
||||
- name: Pull latest changes (kottos)
|
||||
ansible.builtin.command: git pull
|
||||
args:
|
||||
chdir: "{{ kottos_repo_dir }}"
|
||||
when: kottos_clone is not changed
|
||||
changed_when: false
|
||||
|
||||
- name: Create Kottos archive for specified release
|
||||
ansible.builtin.command: git archive -o "{{ kottos_archive_path }}" "{{ kottos_rel }}"
|
||||
args:
|
||||
chdir: "{{ kottos_repo_dir }}"
|
||||
changed_when: true
|
||||
|
||||
# --- Pallas (kottos runtime dependency) --------------------------------
|
||||
- name: Clone Pallas repository if not present
|
||||
ansible.builtin.git:
|
||||
repo: "{{ pallas_repo_url }}"
|
||||
dest: "{{ pallas_repo_dir }}"
|
||||
version: "{{ pallas_rel }}"
|
||||
accept_hostkey: true
|
||||
register: pallas_clone
|
||||
ignore_errors: true
|
||||
|
||||
- name: Fetch all remote branches and tags (pallas)
|
||||
ansible.builtin.command: git fetch --all
|
||||
args:
|
||||
chdir: "{{ pallas_repo_dir }}"
|
||||
when: pallas_clone is not changed
|
||||
changed_when: false
|
||||
|
||||
- name: Pull latest changes (pallas)
|
||||
ansible.builtin.command: git pull
|
||||
args:
|
||||
chdir: "{{ pallas_repo_dir }}"
|
||||
when: pallas_clone is not changed
|
||||
changed_when: false
|
||||
|
||||
- name: Create Pallas archive for specified release
|
||||
ansible.builtin.command: git archive -o "{{ pallas_archive_path }}" "{{ pallas_rel }}"
|
||||
args:
|
||||
chdir: "{{ pallas_repo_dir }}"
|
||||
changed_when: true
|
||||
|
||||
Reference in New Issue
Block a user