feat(desk): install the workstation coding agents against the platform gateway

desk-code installs Visual Studio Code in a selectable flavor (Code - OSS, VSCodium or the Microsoft build), removes the two it does not want because they claim the same binary, and installs the editor extension of every agent role the host also deploys. Only Claude has one: Open VSX carries anthropic.claude-code, while neither Anysphere nor earendil-works publishes an extension there.

desk-agnt-claude and desk-agnt-pi install their agent through the shared npm id and point it at svc-ai-litellm. Both merge into the file the user already keeps rather than replacing it, because ~/.claude/settings.json carries the user's own settings and ~/.pi/agent/models.json their own providers. The pi schema and its default agent directory come from upstream's docs and config.ts, not from a guess.

desk-agnt-cursor installs the editor and configures nothing: the CLI exchanges its key for session tokens and speaks its own protocol, and the editor's base-URL override lives in Cursor's state database rather than in a file a role could render. The README states that instead of the role pretending otherwise.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-09-23 01:59:20 +02:00
1 parent e4dc3b38a1
commit b958322400
36 files changed
+741

No files matched your search

+4
View File
@@ -76,10 +76,13 @@ Every invokable role in the tested lifecycle envelope, with its upstream homepag
| [Bridgy Fed](roles/web-app-bridgy-fed/) | beta | Federation bridge connecting ActivityPub (Fediverse), the AT Protocol (Bluesky), and the IndieWeb | [🌐](https://fed.brid.gy/) [🛠️](roles/web-app-bridgy-fed/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Checkmk](roles/web-app-checkmk/) | beta | Open-source IT and application monitoring server behind SSO with native LDAP user management | [🌐](https://checkmk.com/) [🎬](https://www.youtube.com/watch?v=opO-SOgOJ1I) [🛠️](roles/web-app-checkmk/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Chess](roles/web-app-chess/) | beta | Federated chess server for playing and following rule-validated games over ActivityPub across the Fediverse | [🌐](https://castling.club/) [🛠️](roles/web-app-chess/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Claude Code](roles/desk-agnt-claude/) | alpha | Terminal coding agent from Anthropic, pointed at the platform's own model gateway instead of the vendor API | [🌐](https://code.claude.com/) [🛠️](roles/desk-agnt-claude/README.md#quick-setup) | |
| [Code](roles/desk-code/) | alpha | Visual Studio Code workstation editor in a selectable flavor, carrying the extensions of the agents the host deploys | [🌐](https://github.com/microsoft/vscode) [🛠️](roles/desk-code/README.md#quick-setup) | |
| [Collabora](roles/web-svc-collabora/) | beta | Self-hosted online office backend for real-time in-browser editing of documents, spreadsheets, and presentations | [🌐](https://www.collaboraonline.com/) [🎬](https://www.youtube.com/watch?v=8pqkclWG2BY) [🛠️](roles/web-svc-collabora/README.md#quick-setup) | [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Content Delivery Network](roles/web-svc-cdn/) | beta | Nginx-based content delivery network for serving shared static assets to internal web applications | [🛠️](roles/web-svc-cdn/README.md#quick-setup) | [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Corporate Design](roles/web-svc-css/) | beta | Service-registry role owning the canonical `css` flag and redirecting the CSS hostname to the CDN upstream | [🛠️](roles/web-svc-css/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Coturn](roles/web-svc-coturn/) | beta | Free and open-source TURN/STUN relay server for NAT traversal in WebRTC and real-time communication | [🌐](https://github.com/coturn/coturn) [🛠️](roles/web-svc-coturn/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Prometheus](roles/web-app-prometheus/) |
| [Cursor](roles/desk-agnt-cursor/) | alpha | AI-first code editor installed on the workstation, whose endpoint override stays an operator step | [🌐](https://cursor.com/) [🛠️](roles/desk-agnt-cursor/README.md#quick-setup) | |
| [Dashboard](roles/web-app-dashboard/) | beta | Self-hosted portal for unified access to all deployed applications via a customizable tile and menu interface | [🛠️](roles/web-app-dashboard/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-css/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Simple Icons](roles/web-svc-simpleicons/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Decidim](roles/web-app-decidim/) | beta | Open-source participatory democracy platform for public consultations, civic processes, and community voting | [🌐](https://decidim.org/) [🎬](https://www.youtube.com/watch?v=luSdPZ-wUIY) [🛠️](roles/web-app-decidim/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-app-seaweedfs/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Discourse](roles/web-app-discourse/) | beta | Open-source discussion and community forum platform with moderation, notifications, and plugin support | [🌐](https://www.discourse.org/) [🎬](https://www.youtube.com/watch?v=z3qp_uB46FA) [🛠️](roles/web-app-discourse/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
@@ -156,6 +159,7 @@ Every invokable role in the tested lifecycle envelope, with its upstream homepag
| [Penpot](roles/web-app-penpot/) | beta | Self-hosted design and prototyping platform for UI/UX work, real-time collaboration, and developer handoff | [🌐](https://penpot.app/) [🎬](https://www.youtube.com/watch?v=vAkb4QQmbfk) [🛠️](roles/web-app-penpot/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-app-seaweedfs/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [pgAdmin](roles/web-app-pgadmin/) | beta | Web-based administration and development platform for managing multiple PostgreSQL servers, with optional OAuth2 login | [🌐](https://www.pgadmin.org/) [🎬](https://www.youtube.com/watch?v=WFT5MaZN6g4) [🛠️](roles/web-app-pgadmin/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [PhpMyAdmin](roles/web-app-phpmyadmin/) | beta | Web-based administration tool for MySQL and MariaDB with schema management, querying, and import/export | [🌐](https://www.phpmyadmin.net/) [🛠️](roles/web-app-phpmyadmin/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Pi Coding Agent](roles/desk-agnt-pi/) | alpha | Minimal terminal coding agent with a lazy-loading skill system, wired to the platform's own model gateway | [🌐](https://github.com/earendil-works/pi) [🛠️](roles/desk-agnt-pi/README.md#quick-setup) | |
| [Pixelfed](roles/web-app-pixelfed/) | beta | Decentralized, federated platform for photo sharing and image feeds across the fediverse | [🌐](https://pixelfed.org/) [🛠️](roles/web-app-pixelfed/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-app-seaweedfs/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [PostgreSQL](roles/svc-db-postgres/) | beta | Containerized relational database with automated database, user, and privilege provisioning | [🌐](https://www.postgresql.org/) [🛠️](roles/svc-db-postgres/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [Postmarks](roles/web-app-postmarks/) | beta | Single-user ActivityPub bookmarking site federating public bookmarks to Mastodon and the Fediverse | [🌐](https://github.com/ckolderup/postmarks) [🛠️](roles/web-app-postmarks/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
+76
View File
@@ -0,0 +1,76 @@
# Claude Code
## Description
[Claude Code](https://code.claude.com/) is Anthropic's terminal coding agent. This role installs it on a workstation and points it at the platform's own model gateway instead of the vendor API.
## Overview
The agent speaks the Anthropic Messages API, which the LiteLLM gateway serves alongside its OpenAI routes. The role writes `~/.claude/settings.json` with an `env` block carrying the gateway URL, the workstation's key and the model aliases to use, so every request leaves the machine through the gateway and is accounted there.
The gateway mints its virtual keys from the inventory it is deployed from, and a workstation is deployed from a different one. The key is therefore an operator-supplied credential on the workstation side: mint it on the server, then put it into the workstation inventory.
## Cosmos
The diagram places Claude Code in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).
```mermaid
flowchart LR
subgraph role [desk-agnt-claude 💻]
svc_agnt_claude["agnt-claude"]
end
```
Solid `1:1` edges are fixed relationships; dashed `0..1` edges are conditional (enabled only in matching deployments); red `0..0` edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in `meta/main.yml`.
## Features
- **Gateway-backed:** `ANTHROPIC_BASE_URL` and `ANTHROPIC_AUTH_TOKEN` point the agent at the platform gateway.
- **Explicit models:** `ANTHROPIC_MODEL` and `ANTHROPIC_DEFAULT_HAIKU_MODEL` name gateway aliases, because the vendor's own model ids do not exist there.
- **No configuration without a key:** the settings file is written only once both the gateway URL and the key are set.
- **User-owned:** the file belongs to the workstation user and is readable only by them.
## Quick Setup
### Development
Clone, set up the workstation, and deploy Claude Code onto the local stack:
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=desk-agnt-claude full_cycle=false
```
### Production
Install Claude Code directly onto the target machine: clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
bash scripts/install/package.sh
make install
source scripts/meta/env/load.sh
APP=desk-agnt-claude
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
INVENTORY=inventories/production
infinito administration inventory provision "$INVENTORY" \
--inventory-file "$INVENTORY/devices.yml" \
--host localhost \
--include "$APP" \
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
--password-file "$INVENTORY/.password" \
--diff -vv
```
## Credits
Implemented by **[Kevin Veen-Birkenbach](https://www.veen.world)**.
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code) and maintained by [Kevin Veen-Birkenbach](https://www.veen.world).
Licensed under the [Infinito.Nexus Community License (Non-Commercial)](https://s.infinito.nexus/license).
+5
View File
@@ -0,0 +1,5 @@
---
# nocheck: info-media no official demo video
logo:
class: fas fa-terminal
homepage: https://code.claude.com/
+32
View File
@@ -0,0 +1,32 @@
---
galaxy_info:
author: Kevin Veen-Birkenbach
description: Terminal coding agent from Anthropic, pointed at the platform's own model gateway instead of the vendor API
license: Infinito.Nexus Community License (Non-Commercial)
company: |
Kevin Veen-Birkenbach
https://www.veen.world
galaxy_tags:
- ai
- agent
- cli
- claude
issue_tracker_url: https://s.infinito.nexus/issues
min_ansible_version: "2.9"
platforms:
- name: ArchLinux
versions:
- all
- name: Debian
versions:
- all
- name: EL
versions:
- all
- name: Fedora
versions:
- all
- name: Ubuntu
versions:
- all
dependencies: []
+7
View File
@@ -0,0 +1,7 @@
---
credentials:
gateway_key:
description: Virtual key the gateway minted for this workstation. The gateway deploys from a different inventory than the workstation, so the operator
carries the key over by hand.
algorithm: plain
validation: ^.*$
+14
View File
@@ -0,0 +1,14 @@
---
agnt-claude:
modes:
host:
enabled: true
lifecycle: alpha
gateway_url: ""
model: ""
background_model: ""
min_storage: "500MB"
cpus: "1.0"
mem_reservation: "256m"
mem_limit: "1g"
pids_limit: 512
+16
View File
@@ -0,0 +1,16 @@
---
- name: ✅ Ensure npm is installed
package_install:
id: npm
- name: 📦 install the claude coding agent
ansible.builtin.command:
cmd: npm install -g {{ agnt_claude_package }}
register: agnt_claude_install
changed_when: "'added' in agnt_claude_install.stdout or 'changed' in agnt_claude_install.stdout"
- name: 🔑 Point the agent at the model gateway
ansible.builtin.include_tasks: 01_gateway.yml
when: agnt_claude_configured | bool
- include_tasks: utils/once/flag.yml
@@ -0,0 +1,34 @@
---
- name: 📁 Ensure the agent's configuration directory exists
ansible.builtin.file:
path: "{{ agnt_claude_settings_path | dirname }}"
state: directory
owner: "{{ lookup('users', WORKSTATION_USER).username }}"
group: "{{ lookup('users', WORKSTATION_USER).username }}"
mode: "0700"
- name: 🔎 Look for settings the user already keeps
ansible.builtin.stat:
path: "{{ agnt_claude_settings_path }}"
register: agnt_claude_settings_stat
- name: 📖 Read the settings the user already keeps
ansible.builtin.slurp:
src: "{{ agnt_claude_settings_path }}"
register: agnt_claude_settings_slurp
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
when: agnt_claude_settings_stat.stat.exists
- name: 🧊 Carry the user's settings into the template
ansible.builtin.set_fact:
agnt_claude_existing_settings: "{{ (agnt_claude_settings_slurp.content | b64decode | from_json) if agnt_claude_settings_stat.stat.exists else {} }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: 🔐 Write the merged settings
ansible.builtin.template: # nocheck: stack-host-template (workstation role; the file belongs to the local user and there is no compose stack to gate on)
src: settings.json.j2
dest: "{{ agnt_claude_settings_path }}"
owner: "{{ lookup('users', WORKSTATION_USER).username }}"
group: "{{ lookup('users', WORKSTATION_USER).username }}"
mode: "0600"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
+3
View File
@@ -0,0 +1,3 @@
---
- include_tasks: 00_core.yml
when: run_once_desk_agnt_claude is not defined
@@ -0,0 +1,4 @@
{% set env = agnt_claude_existing_settings.get('env', {}) | combine({'ANTHROPIC_BASE_URL': agnt_claude_gateway_url, 'ANTHROPIC_AUTH_TOKEN': agnt_claude_gateway_key}) %}
{% if agnt_claude_model | length > 0 %}{% set env = env | combine({'ANTHROPIC_MODEL': agnt_claude_model}) %}{% endif %}
{% if agnt_claude_background_model | length > 0 %}{% set env = env | combine({'ANTHROPIC_DEFAULT_HAIKU_MODEL': agnt_claude_background_model}) %}{% endif %}
{{ agnt_claude_existing_settings | combine({'env': env}) | to_nice_json }}
+10
View File
@@ -0,0 +1,10 @@
---
application_id: desk-agnt-claude
agnt_claude_package: "@anthropic-ai/claude-code"
agnt_claude_home: "/home/{{ lookup('users', WORKSTATION_USER).username }}"
agnt_claude_settings_path: "{{ [agnt_claude_home, '.claude', 'settings.json'] | path_join }}"
agnt_claude_gateway_url: "{{ lookup('config', application_id, 'services.agnt-claude.gateway_url') }}"
agnt_claude_model: "{{ lookup('config', application_id, 'services.agnt-claude.model') }}"
agnt_claude_background_model: "{{ lookup('config', application_id, 'services.agnt-claude.background_model') }}"
agnt_claude_gateway_key: "{{ lookup('config', application_id, 'secrets.credentials.gateway_key') }}"
agnt_claude_configured: "{{ (agnt_claude_gateway_url | length > 0) and (agnt_claude_gateway_key | length > 0) }}"
+74
View File
@@ -0,0 +1,74 @@
# Cursor
## Description
[Cursor](https://cursor.com/) is an AI-first code editor. This role installs it on a workstation.
## Overview
Cursor's CLI cannot be pointed at a custom OpenAI-compatible endpoint: it exchanges the key for Cursor session tokens and talks its own protocol afterwards. The editor does carry an "Override OpenAI Base URL" field, but it lives in Cursor's own state database rather than in a file this role could render.
The role therefore installs the editor and leaves the endpoint override to the operator. Nothing here pretends to configure a gateway that the product does not accept from a file.
## Cosmos
The diagram places Cursor in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).
```mermaid
flowchart LR
subgraph role [desk-agnt-cursor 💻]
svc_agnt_cursor["agnt-cursor"]
end
```
Solid `1:1` edges are fixed relationships; dashed `0..1` edges are conditional (enabled only in matching deployments); red `0..0` edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in `meta/main.yml`.
## Features
- **Installed, not faked:** the editor is provisioned; the endpoint override stays a documented operator step.
- **Arch today:** the vendor ships neither a Debian nor an RPM repository, so only the Arch build is wired up.
## Quick Setup
### Development
Clone, set up the workstation, and deploy Cursor onto the local stack:
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=desk-agnt-cursor full_cycle=false
```
### Production
Install Cursor directly onto the target machine: clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
bash scripts/install/package.sh
make install
source scripts/meta/env/load.sh
APP=desk-agnt-cursor
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
INVENTORY=inventories/production
infinito administration inventory provision "$INVENTORY" \
--inventory-file "$INVENTORY/devices.yml" \
--host localhost \
--include "$APP" \
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
--password-file "$INVENTORY/.password" \
--diff -vv
```
## Credits
Implemented by **[Kevin Veen-Birkenbach](https://www.veen.world)**.
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code) and maintained by [Kevin Veen-Birkenbach](https://www.veen.world).
Licensed under the [Infinito.Nexus Community License (Non-Commercial)](https://s.infinito.nexus/license).
+5
View File
@@ -0,0 +1,5 @@
---
# nocheck: info-media no official demo video
logo:
class: fas fa-i-cursor
homepage: https://cursor.com/
+31
View File
@@ -0,0 +1,31 @@
---
galaxy_info:
author: Kevin Veen-Birkenbach
description: AI-first code editor installed on the workstation, whose endpoint override stays an operator step
license: Infinito.Nexus Community License (Non-Commercial)
company: |
Kevin Veen-Birkenbach
https://www.veen.world
galaxy_tags:
- ai
- editor
- cursor
issue_tracker_url: https://s.infinito.nexus/issues
min_ansible_version: "2.9"
platforms:
- name: ArchLinux
versions:
- all
- name: Debian
versions:
- all
- name: EL
versions:
- all
- name: Fedora
versions:
- all
- name: Ubuntu
versions:
- all
dependencies: []
+8
View File
@@ -0,0 +1,8 @@
---
cursor:
Archlinux:
source: aur
names:
- cursor-bin
Debian: [] # nocheck: empty - Cursor ships only as a vendor AppImage and deb outside any Debian or Ubuntu archive; TODO: install the vendor build through a build source once its signature is pinned
RedHat: [] # nocheck: empty - Cursor ships no rpm and is carried by neither Fedora nor EPEL; TODO: install the vendor AppImage through a build source once its signature is pinned
+11
View File
@@ -0,0 +1,11 @@
---
agnt-cursor:
modes:
host:
enabled: true
lifecycle: alpha
min_storage: "1GB"
cpus: "2.0"
mem_reservation: "512m"
mem_limit: "4g"
pids_limit: 1024
+8
View File
@@ -0,0 +1,8 @@
---
- block:
- name: 📦 install cursor
package_install:
id: cursor
- include_tasks: utils/once/flag.yml
when: run_once_desk_agnt_cursor is not defined
+2
View File
@@ -0,0 +1,2 @@
---
application_id: desk-agnt-cursor
+76
View File
@@ -0,0 +1,76 @@
# Pi Coding Agent
## Description
[Pi](https://github.com/earendil-works/pi) is a minimal terminal coding agent with a lazy-loading skill system. This role installs it on a workstation and registers the platform's model gateway as its provider.
## Overview
Pi reads its providers from `~/.pi/agent/models.json`. The role renders that file with one provider of type `openai-completions` pointing at the gateway's `/v1` base, the workstation's key, and the model aliases the operator listed.
As with every workstation agent here, the key is operator-supplied: the gateway mints it from the server inventory, and the workstation inventory carries it.
## Cosmos
The diagram places Pi Coding Agent in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).
```mermaid
flowchart LR
subgraph role [desk-agnt-pi 💻]
svc_agnt_pi["agnt-pi"]
end
```
Solid `1:1` edges are fixed relationships; dashed `0..1` edges are conditional (enabled only in matching deployments); red `0..0` edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in `meta/main.yml`.
## Features
- **Gateway-backed:** one provider entry, no vendor credentials on the machine.
- **Explicit model list:** the aliases come from the inventory, so the agent offers exactly what the gateway serves.
- **No configuration without a key:** the file is written only once URL, key and model list are set.
- **User-owned:** the file belongs to the workstation user and is readable only by them.
## Quick Setup
### Development
Clone, set up the workstation, and deploy Pi Coding Agent onto the local stack:
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=desk-agnt-pi full_cycle=false
```
### Production
Install Pi Coding Agent directly onto the target machine: clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
bash scripts/install/package.sh
make install
source scripts/meta/env/load.sh
APP=desk-agnt-pi
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
INVENTORY=inventories/production
infinito administration inventory provision "$INVENTORY" \
--inventory-file "$INVENTORY/devices.yml" \
--host localhost \
--include "$APP" \
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
--password-file "$INVENTORY/.password" \
--diff -vv
```
## Credits
Implemented by **[Kevin Veen-Birkenbach](https://www.veen.world)**.
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code) and maintained by [Kevin Veen-Birkenbach](https://www.veen.world).
Licensed under the [Infinito.Nexus Community License (Non-Commercial)](https://s.infinito.nexus/license).
+5
View File
@@ -0,0 +1,5 @@
---
# nocheck: info-media no official demo video
logo:
class: fas fa-robot
homepage: https://github.com/earendil-works/pi
+32
View File
@@ -0,0 +1,32 @@
---
galaxy_info:
author: Kevin Veen-Birkenbach
description: Minimal terminal coding agent with a lazy-loading skill system, wired to the platform's own model gateway
license: Infinito.Nexus Community License (Non-Commercial)
company: |
Kevin Veen-Birkenbach
https://www.veen.world
galaxy_tags:
- ai
- agent
- cli
- pi
issue_tracker_url: https://s.infinito.nexus/issues
min_ansible_version: "2.9"
platforms:
- name: ArchLinux
versions:
- all
- name: Debian
versions:
- all
- name: EL
versions:
- all
- name: Fedora
versions:
- all
- name: Ubuntu
versions:
- all
dependencies: []
+7
View File
@@ -0,0 +1,7 @@
---
credentials:
gateway_key:
description: Virtual key the gateway minted for this workstation. The gateway deploys from a different inventory than the workstation, so the operator
carries the key over by hand.
algorithm: plain
validation: ^.*$
+13
View File
@@ -0,0 +1,13 @@
---
agnt-pi:
modes:
host:
enabled: true
lifecycle: alpha
gateway_url: ""
models: []
min_storage: "500MB"
cpus: "1.0"
mem_reservation: "256m"
mem_limit: "1g"
pids_limit: 512
+16
View File
@@ -0,0 +1,16 @@
---
- name: ✅ Ensure npm is installed
package_install:
id: npm
- name: 📦 install the pi coding agent
ansible.builtin.command:
cmd: npm install -g --ignore-scripts {{ agnt_pi_package }}
register: agnt_pi_install
changed_when: "'added' in agnt_pi_install.stdout or 'changed' in agnt_pi_install.stdout"
- name: 🔑 Point the agent at the model gateway
ansible.builtin.include_tasks: 01_gateway.yml
when: agnt_pi_configured | bool
- include_tasks: utils/once/flag.yml
+34
View File
@@ -0,0 +1,34 @@
---
- name: 📁 Ensure the agent's configuration directory exists
ansible.builtin.file:
path: "{{ agnt_pi_models_path | dirname }}"
state: directory
owner: "{{ lookup('users', WORKSTATION_USER).username }}"
group: "{{ lookup('users', WORKSTATION_USER).username }}"
mode: "0700"
- name: 🔎 Look for models the user already keeps
ansible.builtin.stat:
path: "{{ agnt_pi_models_path }}"
register: agnt_pi_models_stat
- name: 📖 Read the models the user already keeps
ansible.builtin.slurp:
src: "{{ agnt_pi_models_path }}"
register: agnt_pi_models_slurp
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
when: agnt_pi_models_stat.stat.exists
- name: 🧊 Carry the user's models into the template
ansible.builtin.set_fact:
agnt_pi_existing_models: "{{ (agnt_pi_models_slurp.content | b64decode | from_json) if agnt_pi_models_stat.stat.exists else {} }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: 🔐 Write the merged model registry
ansible.builtin.template: # nocheck: stack-host-template (workstation role; the file belongs to the local user and there is no compose stack to gate on)
src: models.json.j2
dest: "{{ agnt_pi_models_path }}"
owner: "{{ lookup('users', WORKSTATION_USER).username }}"
group: "{{ lookup('users', WORKSTATION_USER).username }}"
mode: "0600"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
+3
View File
@@ -0,0 +1,3 @@
---
- include_tasks: 00_core.yml
when: run_once_desk_agnt_pi is not defined
@@ -0,0 +1,7 @@
{% set entries = [] %}
{% for alias in agnt_pi_models %}
{% set _ = entries.append({"id": alias}) %}
{% endfor %}
{% set litellm = {"baseUrl": agnt_pi_gateway_url ~ "/v1", "api": "openai-completions", "apiKey": agnt_pi_gateway_key, "models": entries} %}
{% set providers = agnt_pi_existing_models.get('providers', {}) | combine({"litellm": litellm}) %}
{{ agnt_pi_existing_models | combine({"providers": providers}) | to_nice_json }}
+9
View File
@@ -0,0 +1,9 @@
---
application_id: desk-agnt-pi
agnt_pi_package: "@earendil-works/pi-coding-agent"
agnt_pi_home: "/home/{{ lookup('users', WORKSTATION_USER).username }}"
agnt_pi_models_path: "{{ [agnt_pi_home, '.pi', 'agent', 'models.json'] | path_join }}"
agnt_pi_gateway_url: "{{ lookup('config', application_id, 'services.agnt-pi.gateway_url') }}"
agnt_pi_models: "{{ lookup('config', application_id, 'services.agnt-pi.models') }}"
agnt_pi_gateway_key: "{{ lookup('config', application_id, 'secrets.credentials.gateway_key') }}"
agnt_pi_configured: "{{ (agnt_pi_gateway_url | length > 0) and (agnt_pi_gateway_key | length > 0) and (agnt_pi_models | length > 0) }}"
+78
View File
@@ -0,0 +1,78 @@
# Code
## Description
[Visual Studio Code](https://github.com/microsoft/vscode) in a selectable flavor: the distribution's Code - OSS build, VSCodium, or Microsoft's own binary.
## Overview
`services.code.flavor` picks one of `code-oss`, `vscodium` or `vscode`. The three builds conflict at package level, so the role removes the other two before installing the chosen one.
The role also carries the editor extensions of the agents the same host deploys: when `desk-agnt-claude` is in the host's groups, the Claude Code extension is installed into the chosen flavor. Code - OSS and VSCodium resolve extensions through Open VSX, which carries that extension as well.
`desk-agnt-cursor` and `desk-agnt-pi` carry no entry in that map. Cursor is a full editor rather than an extension, and neither vendor publishes an extension on Open VSX, so there is nothing to install into Code for them. Both agents are used from their own binary.
## Cosmos
The diagram places Code in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).
```mermaid
flowchart LR
subgraph role [desk-code 💻]
svc_code["code"]
end
```
Solid `1:1` edges are fixed relationships; dashed `0..1` edges are conditional (enabled only in matching deployments); red `0..0` edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in `meta/main.yml`.
## Features
- **Flavor selectable:** one setting switches between Code - OSS, VSCodium and the Microsoft build.
- **Conflict-free switch:** the other flavors are removed first, because they claim the same binary.
- **Agent-aware:** an agent role on the same host brings its editor extension along.
- **Refused early:** an unknown flavor aborts the deploy with the list of carried flavors.
## Quick Setup
### Development
Clone, set up the workstation, and deploy Code onto the local stack:
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=desk-code full_cycle=false
```
### Production
Install Code directly onto the target machine: clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):
```bash
git clone https://github.com/infinito-nexus/core.git
cd core
bash scripts/install/package.sh
make install
source scripts/meta/env/load.sh
APP=desk-code
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
INVENTORY=inventories/production
infinito administration inventory provision "$INVENTORY" \
--inventory-file "$INVENTORY/devices.yml" \
--host localhost \
--include "$APP" \
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
--password-file "$INVENTORY/.password" \
--diff -vv
```
## Credits
Implemented by **[Kevin Veen-Birkenbach](https://www.veen.world)**.
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code) and maintained by [Kevin Veen-Birkenbach](https://www.veen.world).
Licensed under the [Infinito.Nexus Community License (Non-Commercial)](https://s.infinito.nexus/license).
+5
View File
@@ -0,0 +1,5 @@
---
# nocheck: info-media no official demo video
logo:
class: fas fa-code
homepage: https://github.com/microsoft/vscode
+32
View File
@@ -0,0 +1,32 @@
---
galaxy_info:
author: Kevin Veen-Birkenbach
description: Visual Studio Code workstation editor in a selectable flavor, carrying the extensions of the agents the host deploys
license: Infinito.Nexus Community License (Non-Commercial)
company: |
Kevin Veen-Birkenbach
https://www.veen.world
galaxy_tags:
- editor
- ide
- vscode
- workstation
issue_tracker_url: https://s.infinito.nexus/issues
min_ansible_version: "2.9"
platforms:
- name: ArchLinux
versions:
- all
- name: Debian
versions:
- all
- name: EL
versions:
- all
- name: Fedora
versions:
- all
- name: Ubuntu
versions:
- all
dependencies: []
+22
View File
@@ -0,0 +1,22 @@
---
code-oss:
Archlinux:
- code
Debian: [] # nocheck: empty - Debian and Ubuntu archive no Code - OSS build; TODO: install the VSCodium apt repository build through a repo source
RedHat: [] # nocheck: empty - Fedora and CentOS Stream archive no Code - OSS build; TODO: install the VSCodium rpm repository build through a repo source
vscode:
Archlinux:
source: aur
names:
- visual-studio-code-bin
Debian: [] # nocheck: empty - Visual Studio Code is proprietary and shipped only from Microsoft's own apt repository; TODO: add that repository through a repo source
RedHat: [] # nocheck: empty - Visual Studio Code is proprietary and shipped only from Microsoft's own rpm repository; TODO: add that repository through a repo source
vscodium:
Archlinux:
source: aur
names:
- vscodium-bin
Debian: [] # nocheck: empty - VSCodium ships its own signed apt repository rather than a Debian or Ubuntu package; TODO: add that repository through a repo source
RedHat: [] # nocheck: empty - VSCodium ships its own signed rpm repository rather than a Fedora or EPEL package; TODO: add that repository through a repo source
+12
View File
@@ -0,0 +1,12 @@
---
code:
modes:
host:
enabled: true
lifecycle: alpha
flavor: code-oss
min_storage: "1GB"
cpus: "2.0"
mem_reservation: "512m"
mem_limit: "4g"
pids_limit: 1024
+28
View File
@@ -0,0 +1,28 @@
---
- name: "🛑 Refuse a flavor the role does not carry"
ansible.builtin.assert:
that:
- code_flavor in code_flavors
fail_msg: "services.code.flavor is '{{ code_flavor }}'; carried flavors are {{ code_flavors.keys() | list | join(', ') }}."
quiet: true
- name: "🧹 Remove the flavors that conflict with {{ code_flavor }}"
package_install:
id: "{{ item }}"
state: absent
loop: "{{ code_conflicting_flavors }}"
- name: "📦 install {{ code_flavor }}"
package_install:
id: "{{ code_flavor }}"
- name: "🧩 Install the extension of an agent this host deploys"
ansible.builtin.command:
cmd: "{{ code_binary }} --install-extension {{ item }} --force"
become: false
become_user: "{{ lookup('users', WORKSTATION_USER).username }}"
register: code_extension
changed_when: "'successfully installed' in (code_extension.stdout | lower)"
loop: "{{ code_wanted_extensions }}"
- include_tasks: utils/once/flag.yml
+3
View File
@@ -0,0 +1,3 @@
---
- include_tasks: 00_core.yml
when: run_once_desk_code is not defined
+15
View File
@@ -0,0 +1,15 @@
---
application_id: desk-code
code_flavor: "{{ lookup('config', application_id, 'services.code.flavor') }}"
code_flavors:
code-oss:
binary: code
vscodium:
binary: codium
vscode:
binary: code
code_binary: "{{ code_flavors[code_flavor].binary }}"
code_conflicting_flavors: "{{ code_flavors.keys() | reject('equalto', code_flavor) | list }}"
code_agent_extensions:
desk-agnt-claude: anthropic.claude-code
code_wanted_extensions: "{{ code_agent_extensions | dict2items | selectattr('key', 'in', group_names) | map(attribute='value') | list }}"