This commit is contained in:
Nicolas Cantu 2026-03-21 17:43:45 +01:00
commit 74cd0050d8
14 changed files with 901 additions and 0 deletions

View File

@ -0,0 +1,3 @@
# Alias for AnythingLLM: name requested by operator.
# Base: Qwen3 Coder (cloud). For full local weights use: FROM qwen3-coder:latest
FROM qwen3-coder:480b-cloud

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# smart_ide — IDE orienté intention et IA locale
Projet denvironnement de développement où l**inférence** repose sur **Ollama**, la **mémoire documentaire et RAG** sur **AnythingLLM**, et la bureautique métier sur **ONLYOFFICE**. Les **agents métier** existants (`ia_dev` et sous-agents) restent le noyau opératoire ; léditeur et lorchestrateur les exposent via une **grammaire de commandes** plutôt que via une navigation fichiers classique.
## Première cible de déploiement
Le **premier déploiement** visé est un **poste Linux client** qui se connecte en **SSH** à un **serveur distant** hébergeant :
- le **socle technique IA** (Ollama, AnythingLLM, services associés) ;
- les **dépôts** (sources, agents, procédures).
LUX (ex. Lapce) et les flux utilisateur peuvent tourner sur le client ; lexécution lourde, la mémoire projet et Git vivent **sur le serveur**. Détail : [docs/deployment-target.md](./docs/deployment-target.md).
## Positionnement
- **Pas dexplorer comme surface principale** : la navigation primaire passe par intentions, recherche, contexte, timeline, objets logiques et artefacts ; un accès brut (fichiers / arborescence) reste disponible en **mode expert / secours**, pas comme flux nominal.
- **Machine de travail orientée opérations** plutôt quéditeur de fichiers : lutilisateur exprime *ce quil veut faire*, *sur quel objet logique*, *avec quels droits*, *dans quel contexte projet*, *avec quelle procédure*, *avec quel agent*, *avec quel résultat attendu*.
- **Socle éditeur envisagé : [Lapce](https://lapce.dev/)** — open source, Rust, rendu natif / GPU, positionné comme éditeur rapide et léger : base cohérente pour un noyau dédition + agents, sans empiler lhistorique complet dun IDE classique. Choix darchitecture, pas une obligation figée.
## AnythingLLM et projets
Pour chaque **projet**, un **workspace AnythingLLM** dédié est créé (ou rattaché) : corpus, embeddings et conversations restent **isolés par projet**. Une **moulinette de synchronisation** aligne un sous-ensemble de fichiers du dépôt avec le workspace concerné afin de garder la mémoire RAG alignée avec le code et la doc utiles.
Voir [docs/anythingllm-workspaces.md](./docs/anythingllm-workspaces.md).
## Documentation
| Document | Contenu |
|----------|---------|
| [docs/README.md](./docs/README.md) | Index de la documentation technique |
| [docs/infrastructure.md](./docs/infrastructure.md) | LAN, SSH, scripts daccès hôte |
| [docs/services.md](./docs/services.md) | Ollama, AnythingLLM Docker, intégration |
| [docs/anythingllm-workspaces.md](./docs/anythingllm-workspaces.md) | Workspaces par projet, synchronisation |
| [docs/ux-navigation-model.md](./docs/ux-navigation-model.md) | Remplacer lexplorer : intentions, risques, vues, graphe, mode expert |
| [docs/system-architecture.md](./docs/system-architecture.md) | Couches, modules, agents, gateway, OpenShell, événements |
| [docs/deployment-target.md](./docs/deployment-target.md) | Client Linux + SSH : serveur = socle IA + repos |
## Dépôt actuel (outillage)
Scripts dinstallation et dexploitation sur Ubuntu : SSH, sudo ciblé, AnythingLLM Docker, Ollama exposé pour Docker, modèle Ollama alias `qwen3-code-webdev`, installer Desktop AnythingLLM. Ces scripts ciblent en priorité l**hôte serveur** qui porte le socle IA et les repos ; le **client Linux** repose surtout sur SSH et lIDE. LIDE complet (Lapce + orchestrateur + gateway) est **cible de conception** ; ce dépôt documente et supporte la **stack sur serveur** (Ollama + AnythingLLM) et laccès distant.
**Auteur :** Équipe 4NK

142
add-ssh-key.sh Executable file
View File

@ -0,0 +1,142 @@
#!/bin/bash
# Add SSH public key to ~/.ssh/authorized_keys on infrastructure hosts.
#
# Modes (pick one):
# ADD_KEY_LOCAL=1 — you are already SSH'd on the target host (e.g. 192.168.1.164): only
# update the current user's ~/.ssh/authorized_keys on this machine.
# LAN_DIRECT=1 — same LAN as hosts: ssh BACKEND_USER@192.168.1.x directly (no ProxyJump,
# no 4nk.myftp.biz). Host list includes proxy .100, backends, and .164.
# (default) — bastion JUMP then ProxyJump to each backend (Internet / standard doc).
#
# The key embedded below (desk@desk) is what gets appended remotely; client auth uses your
# existing keys (SSH_IDENTITY_FILE / agent).
#
# Run as the SSH user, not root: sudo uses /root/.ssh and causes Permission denied (publickey).
#
# Optional env:
# BACKEND_USER=ncantu
# JUMP=ncantu@4nk.myftp.biz # default jump host when LAN_DIRECT is unset
# SSH_IDENTITY_FILE=~/.ssh/id_ed25519
# SSH_VERBOSE=1
# EXTRA_LAN_IPS="192.168.1.42 ..." # space-separated, appended when LAN_DIRECT=1
# Usage:
# ADD_KEY_LOCAL=1 ./add-ssh-key.sh
# LAN_DIRECT=1 ./add-ssh-key.sh
set -euo pipefail
SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDyLeCZh0tJ7rEp1sktpMlA2EaBBKBU5jNRMgboYAOsk desk@desk"
KEY_FINGERPRINT="AAAAC3NzaC1lZDI1NTE5AAAAIDyLeCZh0tJ7rEp1sktpMlA2EaBBKBU5jNRMgboYAOsk"
JUMP="${JUMP:-ncantu@4nk.myftp.biz}"
BACKEND_USER="${BACKEND_USER:-ncantu}"
BACKEND_IPS=(
"192.168.1.101" # test
"192.168.1.102" # pprod
"192.168.1.103" # prod
"192.168.1.104" # services
"192.168.1.105" # bitcoin
"192.168.1.173" # ia
)
LAN_IPS=(
"192.168.1.100" # proxy
"${BACKEND_IPS[@]}"
"192.168.1.164" # workstation / host 164 on LAN
)
SSH_OPTS=(
-o StrictHostKeyChecking=accept-new
)
if [ -n "${SSH_IDENTITY_FILE:-}" ]; then
idf="${SSH_IDENTITY_FILE/#\~/$HOME}"
SSH_OPTS+=(-i "$idf" -o IdentitiesOnly=yes)
fi
if [ -n "${SSH_VERBOSE:-}" ]; then
SSH_OPTS+=(-v)
fi
if [ "$(id -u)" -eq 0 ]; then
echo "Do not run this script with sudo/root: SSH will use /root/.ssh and fail with Permission denied (publickey)." >&2
exit 1
fi
add_key_to_current_user() {
local auth="${HOME}/.ssh/authorized_keys"
mkdir -p "${HOME}/.ssh"
chmod 700 "${HOME}/.ssh"
touch "${auth}"
chmod 600 "${auth}"
if ! grep -qF "${KEY_FINGERPRINT}" "${auth}" 2>/dev/null; then
printf '%s\n' "${SSH_KEY}" >> "${auth}"
echo "Key added (local user $(whoami)@$(hostname -f 2>/dev/null || hostname))"
else
echo "Key already present (local user $(whoami)@$(hostname -f 2>/dev/null || hostname))"
fi
}
run_add_key_remote() {
local -a ssh_cmd=("$@")
"${ssh_cmd[@]}" bash -s <<EOF
set -euo pipefail
KEY_FINGERPRINT='${KEY_FINGERPRINT}'
KEY_LINE='${SSH_KEY}'
AUTH="\${HOME}/.ssh/authorized_keys"
mkdir -p "\${HOME}/.ssh"
chmod 700 "\${HOME}/.ssh"
touch "\${AUTH}"
chmod 600 "\${AUTH}"
if ! grep -qF "\${KEY_FINGERPRINT}" "\${AUTH}" 2>/dev/null; then
printf '%s\n' "\${KEY_LINE}" >> "\${AUTH}"
echo "Key added"
else
echo "Key already present"
fi
EOF
}
if [ "${ADD_KEY_LOCAL:-0}" = "1" ]; then
echo "ADD_KEY_LOCAL=1: updating authorized_keys for current user only."
echo "Key: $SSH_KEY"
echo "Host: $(hostname) (${USER})"
add_key_to_current_user
exit 0
fi
if [ "${LAN_DIRECT:-0}" = "1" ]; then
echo "LAN_DIRECT=1: direct SSH on LAN (no ProxyJump / no bastion hostname)."
echo "Key: $SSH_KEY"
echo "User: ${BACKEND_USER}"
if [ -n "${EXTRA_LAN_IPS:-}" ]; then
# shellcheck disable=SC2206
extra_ips=( ${EXTRA_LAN_IPS} )
LAN_IPS+=( "${extra_ips[@]}" )
fi
for ip in "${LAN_IPS[@]}"; do
echo ""
echo "Processing: ${BACKEND_USER}@${ip}"
run_add_key_remote ssh "${SSH_OPTS[@]}" "${BACKEND_USER}@${ip}"
done
echo ""
echo "SSH key addition completed (LAN direct)."
exit 0
fi
echo "Adding SSH key to all servers (bastion + ProxyJump)..."
echo "Key: $SSH_KEY"
echo "Jump: $JUMP"
echo ""
echo "Processing bastion (proxy): ${JUMP}"
run_add_key_remote ssh "${SSH_OPTS[@]}" "$JUMP"
echo ""
for ip in "${BACKEND_IPS[@]}"; do
echo "Processing backend: ${BACKEND_USER}@${ip} (via ${JUMP})"
run_add_key_remote ssh "${SSH_OPTS[@]}" -J "$JUMP" "${BACKEND_USER}@${ip}"
echo ""
done
echo "SSH key addition completed for bastion and all listed backends."

20
add-sudo-nopasswd-ncantu.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
# Add passwordless sudo for user ncantu.
# Must be run as root (e.g. sudo ./add-sudo-nopasswd-ncantu.sh).
# Creates /etc/sudoers.d/99-ncantu-nopasswd and validates with visudo -c.
set -euo pipefail
SUDOERS_FILE="/etc/sudoers.d/99-ncantu-nopasswd"
USER_NAME="ncantu"
if [ "$(id -u)" -ne 0 ]; then
echo "Run as root: sudo $0" >&2
exit 1
fi
echo "${USER_NAME} ALL=(ALL) NOPASSWD: ALL" > "${SUDOERS_FILE}"
chmod 440 "${SUDOERS_FILE}"
visudo -c -f "${SUDOERS_FILE}"
echo "Done. User ${USER_NAME} can run sudo without password."

22
configure-ollama-for-docker.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
# Expose Ollama on all interfaces so Docker containers (AnythingLLM) can reach it via
# host.docker.internal (--add-host=host.docker.internal:host-gateway).
# Requires sudo. Idempotent.
set -euo pipefail
if [ "$(id -u)" -ne 0 ]; then
echo "Run: sudo $0" >&2
exit 1
fi
mkdir -p /etc/systemd/system/ollama.service.d
cat <<'EOF' > /etc/systemd/system/ollama.service.d/override.conf
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
EOF
systemctl daemon-reload
systemctl restart ollama
echo "Ollama listens on 0.0.0.0:11434 (check: ss -tlnp | grep 11434)"

21
docs/README.md Normal file
View File

@ -0,0 +1,21 @@
# smart_ide — documentation
Operational, architectural, and UX-design notes for the local-AI IDE initiative and the host tooling in this repository.
| Document | Content |
|----------|---------|
| [../README.md](../README.md) | Project overview (French): vision, Lapce, AnythingLLM per project |
| [deployment-target.md](./deployment-target.md) | First target: Linux client + SSH remote server (AI stack + repos) |
| [infrastructure.md](./infrastructure.md) | Host inventory (LAN), SSH key workflow, host scripts |
| [services.md](./services.md) | Ollama, AnythingLLM (Docker), Desktop installer, Ollama ↔ Docker |
| [anythingllm-workspaces.md](./anythingllm-workspaces.md) | One AnythingLLM workspace per project; sync pipeline |
| [ux-navigation-model.md](./ux-navigation-model.md) | Beyond file explorer: intentions, graph, palette, risks, expert mode |
| [system-architecture.md](./system-architecture.md) | Layers, modules, agent gateway, OpenShell, events, Lapce |
**Author:** 4NK
**Related external docs**
- AnythingLLM Docker: <https://docs.anythingllm.com/installation-docker/local-docker>
- Ollama: <https://github.com/ollama/ollama/blob/main/docs/linux.md>
- Lapce: <https://lapce.dev/>

View File

@ -0,0 +1,16 @@
# AnythingLLM — workspaces par projet
## Principe
- Un **workspace AnythingLLM** est créé (ou associé) **par projet** : documents indexés, embeddings, threads et paramètres RAG sont **scopés au projet**, pas mélangés entre dépôts.
- Cela permet à la mémoire interrogée par `ask` / les agents de rester **pertinente** et **traçable** par contexte métier.
## Synchronisation avec le dépôt
- Une **moulinette** (pipeline de synchro) met à jour le workspace à partir de fichiers sélectionnés du dépôt : sources, doc, configs exposées volontairement, etc.
- Les règles de ce quon synchronise (inclusions / exclusions, secrets interdits) doivent être **explicites** et alignées avec la politique de sécurité du projet.
## Exploitation
- Instance Docker décrite dans [services.md](./services.md) : stockage hôte typiquement sous `$HOME/anythingllm` sur l**hôte qui exécute le conteneur** — en **première cible de déploiement**, cet hôte est le **serveur distant** (SSH), pas obligatoirement le poste Linux client ; la création de **plusieurs workspaces** se fait dans lUI AnythingLLM (ou via API) en conservant la convention « un workspace = un projet ».
- Lorchestrateur IDE décide **quand** interroger AnythingLLM (voir [system-architecture.md](./system-architecture.md)). LURL vue depuis le client peut exiger un **tunnel SSH** ou un rebond réseau : [deployment-target.md](./deployment-target.md).

25
docs/deployment-target.md Normal file
View File

@ -0,0 +1,25 @@
# Première cible de déploiement — client Linux + serveur distant (SSH)
## Modèle
La **première cible de déploiement** nest pas un poste tout-en-un sur la même machine que le socle IA.
| Rôle | Où ça tourne | Contenu typique |
|------|----------------|-----------------|
| **Client** | Machine **Linux** de lutilisateur (poste local) | Shell dédition / UX (ex. Lapce), orchestrateur côté client si applicable, connexion **SSH** persistante ou à la demande |
| **Serveur distant** | Hôte joignable en **SSH** (LAN, bastion, ou jump host selon linfra) | **Socle technique IA** (Ollama, AnythingLLM Docker, services associés), **clones des dépôts**, exécution des **agents** / scripts / OpenShell sur le périmètre autorisé |
Lutilisateur travaille depuis un **Linux client** ; le **calcul**, les **modèles**, la **mémoire RAG** et les **sources de vérité Git** résident sur le **serveur** (ou une ferme de serveurs derrière la même session SSH).
## Conséquences
- Les URLs « locales » du serveur (`localhost:11434`, `localhost:3001`, …) sont **locales au serveur**. Depuis le client, laccès passe par **tunnel SSH** (`-L`), **ProxyJump**, ou configuration explicite (hostname interne, VPN) selon la politique réseau.
- L**agent gateway** et le **policy-runtime** (OpenShell) sexécutent idéalement **là où tournent les agents et les repos** — le serveur — sauf décision contraire documentée.
- Le **workspace AnythingLLM par projet** vit **côté serveur** (stockage du conteneur ou chemin monté sur lhôte distant). La moulinette de synchro lit les **dépôts sur le serveur**.
- Le client doit disposer dune **identité SSH** autorisée sur le serveur (voir `add-ssh-key.sh` et [infrastructure.md](./infrastructure.md)).
## Documentation liée
- Topologie LAN / bastion : [infrastructure.md](./infrastructure.md)
- Services Ollama / AnythingLLM sur lhôte qui **héberge** le socle : [services.md](./services.md)
- Répartition logique des modules : [system-architecture.md](./system-architecture.md) (à lire avec ce découpage physique)

58
docs/infrastructure.md Normal file
View File

@ -0,0 +1,58 @@
# Infrastructure
## Scope
This repository ships shell scripts used on Ubuntu workstations and related LAN hosts. It does **not** define cloud Terraform or CI; it documents how those scripts map to the **private LAN** layout used with the 4NK bastion model.
## First deployment shape (client / server)
The **primary deployment target** is a **Linux client** that connects over **SSH** to a **remote server** where the **AI stack** (Ollama, AnythingLLM, etc.) and **Git repositories** live. Install scripts in this repo apply mainly to that **server** (or to a LAN workstation that plays the same role). The client uses SSH (and optionally port forwarding) to reach services that bind to the servers loopback or internal interfaces. See [deployment-target.md](./deployment-target.md).
## LAN host roles (reference)
Private segment **192.168.1.0/24** (DHCP with MAC reservations). The table matches the host lists in `add-ssh-key.sh`.
| IP | Role |
|----|------|
| 192.168.1.100 | Proxy / bastion (public entry via DynDNS `4nk.myftp.biz`) |
| 192.168.1.101 | test |
| 192.168.1.102 | pre-production |
| 192.168.1.103 | production |
| 192.168.1.104 | services (Git, Mempool, Rocket.Chat, …) |
| 192.168.1.105 | bitcoin |
| 192.168.1.173 | ia |
| 192.168.1.164 | Example workstation on LAN (included in `LAN_DIRECT` list) |
Internet access to backends uses **SSH ProxyJump** via `ncantu@4nk.myftp.biz` (see `JUMP` in `add-ssh-key.sh`). On the same LAN, direct `ssh ncantu@192.168.1.x` is valid.
## Scripts (infrastructure / access)
### `add-ssh-key.sh`
Appends a fixed **Ed25519 public key** (comment `desk@desk`) to `~/.ssh/authorized_keys` on target hosts.
| Mode | When to use |
|------|-------------|
| Default | From a machine that can reach `JUMP` (`ncantu@4nk.myftp.biz`), then ProxyJump to each backend IP. |
| `LAN_DIRECT=1` | Same LAN: direct SSH to each IP in `LAN_IPS` (proxy, backends, `.164`). No bastion hostname. |
| `ADD_KEY_LOCAL=1` | Already logged in on the target host: update **current user** only (e.g. workstation `.164`). |
**Do not run with `sudo`:** the SSH client would use `/root/.ssh` and fail with `Permission denied (publickey)`.
**Environment (optional):** `JUMP`, `BACKEND_USER`, `SSH_IDENTITY_FILE`, `SSH_VERBOSE=1`, `EXTRA_LAN_IPS` (with `LAN_DIRECT=1`).
### `add-sudo-nopasswd-ncantu.sh`
One-time **root** execution: creates `/etc/sudoers.d/99-ncantu-nopasswd` with `ncantu ALL=(ALL) NOPASSWD: ALL`, `chmod 440`, `visudo -c`. Use only where this policy is explicitly required.
## Data paths (host)
| Path | Purpose |
|------|---------|
| `$HOME/anythingllm` | AnythingLLM Docker bind mount (storage + `.env`), default from `install-anythingllm-docker.sh` |
| `$HOME/.ssh/authorized_keys` | SSH access; updated by `add-ssh-key.sh` modes |
## Security notes
- SSH is key-based; the embedded key in `add-ssh-key.sh` is for a designated client (`desk@desk`). Rotate or replace in script if the key is compromised.
- Passwordless sudo reduces interactive friction and **increases** local privilege impact; scope to trusted machines only.

88
docs/services.md Normal file
View File

@ -0,0 +1,88 @@
# Services
## Where these services run (first deployment)
For the **first deployment target**, Ollama and AnythingLLM run on the **remote SSH server** that hosts the AI stack and repositories, not necessarily on the users Linux laptop. Access from the client may use **SSH local forwarding** or internal hostnames. See [deployment-target.md](./deployment-target.md).
## Overview
| Service | Delivery | Default URL / port | Config / persistence |
|---------|----------|--------------------|------------------------|
| Ollama | systemd (`ollama.service`) | `http://127.0.0.1:11434` (API) | Models under Ollama data dir; listen address via systemd override |
| AnythingLLM | Docker (`mintplexlabs/anythingllm`) | `http://localhost:3001` | `$HOME/anythingllm` + `.env` bind-mounted ; **one workspace per project** (see [anythingllm-workspaces.md](./anythingllm-workspaces.md)) |
| AnythingLLM Desktop | AppImage (optional) | local Electron app | User profile under `~/.config/anythingllm-desktop` (installer) |
## Ollama
- **Install:** official script `https://ollama.com/install.sh` (used on target Ubuntu hosts).
- **Service:** `systemctl enable --now ollama` (handled by installer).
- **Default bind:** loopback only (`127.0.0.1:11434`), which **blocks** Docker containers on the same host from calling Ollama.
### Expose Ollama to Docker on the same host
Run **`configure-ollama-for-docker.sh`** as root (or equivalent):
- Drop-in: `/etc/systemd/system/ollama.service.d/override.conf`
- `Environment="OLLAMA_HOST=0.0.0.0:11434"`
- `systemctl daemon-reload && systemctl restart ollama`
Verify: `ss -tlnp | grep 11434` shows `*:11434`.
### Models (reference)
- Embeddings for AnythingLLM + Ollama: `ollama pull nomic-embed-text`
- Custom name **`qwen3-code-webdev`:** not in the public Ollama library as-is; this repo includes `Modelfile-qwen3-code-webdev` defining an alias (default base: `qwen3-coder:480b-cloud`). Rebuild with `ollama create qwen3-code-webdev -f Modelfile-qwen3-code-webdev` after editing `FROM`.
## AnythingLLM (Docker)
### Workspaces and projects
AnythingLLM is used with **dedicated workspaces per project** so RAG memory, documents, and threads stay isolated. A **sync job** (“moulinette”) keeps selected repository files aligned with each workspace. Operational rules: [anythingllm-workspaces.md](./anythingllm-workspaces.md).
**Script:** `install-anythingllm-docker.sh`
- **Image:** `mintplexlabs/anythingllm` (override with `ANYTHINGLLM_IMAGE`).
- **Container name:** `anythingllm` (override with `ANYTHINGLLM_CONTAINER_NAME`).
- **Ports:** `HOST_PORT:3001` (default `3001:3001`).
- **Capabilities:** `--cap-add SYS_ADMIN` (Chromium / document features in container).
- **Networking:** `--add-host=host.docker.internal:host-gateway` so the app can reach Ollama on the host at `http://host.docker.internal:11434` once `OLLAMA_HOST` is set as above.
- **Volumes:**
- `${STORAGE_LOCATION}:/app/server/storage`
- `${STORAGE_LOCATION}/.env:/app/server/.env`
Re-running the script **removes** the existing container by name and starts a new one; data remains in `STORAGE_LOCATION` if the bind path is unchanged.
### Configure LLM provider (Ollama)
In `$STORAGE_LOCATION/.env` (mounted into the container), set at minimum:
- `LLM_PROVIDER='ollama'`
- `OLLAMA_BASE_PATH='http://host.docker.internal:11434'`
- `OLLAMA_MODEL_PREF='<model name>'` (e.g. `qwen3-code-webdev`)
- `EMBEDDING_ENGINE='ollama'`
- `EMBEDDING_BASE_PATH='http://host.docker.internal:11434'`
- `EMBEDDING_MODEL_PREF='nomic-embed-text:latest'`
- `VECTOR_DB='lancedb'` (default stack)
See upstream `.env.example`:
<https://raw.githubusercontent.com/Mintplex-Labs/anything-llm/master/docker/.env.example>
After editing `.env`, restart the container: `docker restart anythingllm`.
## AnythingLLM Desktop (AppImage)
**Script:** `installer.sh` — downloads the official AppImage, optional AppArmor profile, `.desktop` entry. Interactive prompts; not a headless service.
- Documentation: <https://docs.anythingllm.com>
- Use **either** Docker **or** Desktop on the same machine if you want to avoid conflicting ports and duplicate workspaces.
## Operational checks
```bash
systemctl is-active ollama
curl -sS http://127.0.0.1:11434/api/tags | head
docker ps --filter name=anythingllm
docker exec anythingllm sh -c 'curl -sS http://host.docker.internal:11434/api/tags | head'
```
The last command must succeed after `OLLAMA_HOST=0.0.0.0:11434` and `host.docker.internal` are configured.

111
docs/system-architecture.md Normal file
View File

@ -0,0 +1,111 @@
# Architecture système — IDE, agents, runtime, mémoire
## Répartition physique (première cible)
Pour le **premier déploiement**, un **poste Linux** (client) établit des sessions **SSH** vers un **serveur** qui concentre :
- Ollama, AnythingLLM (et extensions du socle IA) ;
- les **dépôts** et lexécution des **agents** / OpenShell sur chemins autorisés.
L**éditeur** et une partie de lUX peuvent rester sur le client ; le **gateway**, le **policy-runtime** et les **knowledge-services** (fichiers RAG, workspaces AnythingLLM) sont cohérents **côté serveur**, sauf architecture hybride explicitement documentée. Voir [deployment-target.md](./deployment-target.md).
## Couches fonctionnelles (vue cible)
| Couche | Rôle |
|--------|------|
| **Agents `ia_dev`** | Noyau **métier et opératoire** (existant) ; sous-agents, recettes, tools |
| **OpenShell** | **Sécurité et exécution** : sandboxes, politiques, résolution contrôlée |
| **Éditeur (ex. Lapce)** | **Interaction** : texte léger, terminal, palette, timeline, UX intentionnelle |
| **Orchestrateur maison** | **Routage** : pas « dintelligence » au sens LLM, mais décision de flux |
| **Ollama** | Backend d**inférence** locale |
| **AnythingLLM** | **Mémoire documentaire** et RAG ; **un workspace par projet** ([anythingllm-workspaces.md](./anythingllm-workspaces.md)) |
| **ONLYOFFICE** | Backend **documentaire métier** (documents, feuilles, présentations) |
Flux type : demande utilisateur → orchestrateur → préparation (scripts / tools génériques) → agents → besoin LLM → Ollama ; besoin doc / RAG → AnythingLLM ; besoin bureautique → ONLYOFFICE.
## Orchestrateur — décisions de routage
Décider notamment :
- quelle **commande** utilisateur appelle quel **agent principal** ;
- quel agent appelle quel **sous-agent** ;
- quand privilégier un **script** vs un **tool générique** vs `ia_dev` ;
- quand `ia_dev` peut **escalader** vers Ollama ;
- quand interroger **AnythingLLM** ;
- quand passer par **ONLYOFFICE** ;
- quand **refuser**.
## Descripteur stable par agent
Chaque agent devrait exposer au minimum : **nom**, **rôle**, **entrées**, **sorties**, **droits**, **dépendances**, **scripts** appelés, **modèles** éventuels, **préconditions**, **postconditions**, **timeouts**, **coût**, **niveau de risque**.
Un **protocole unique** couvre les implémentations hétérogènes (script, workflow, wrapper doutil, appel IA).
Hiérarchie agent → sous-agent : à **formaliser** explicitement pour éviter un graphe implicite ingouvernable.
## Événements normalisés (exemples)
`started`, `tool_selected`, `script_started`, `model_called`, `waiting_validation`, `completed`, `failed`, `rolled_back`, `artifact_created`.
Sortie **événementielle uniforme** vers léditeur ; **journalisation** ; possibilité de **rejouer**, diagnostiquer, **convertir en recette** stable.
## Sécurité — OpenShell central
- Chaque nouvelle résolution devrait pouvoir devenir **recipe**, **tool** ou **sous-agent** stable (travail des commandes UX de haut niveau).
- Les agents ne devraient **pas** exécuter directement sur lhôte sans contrôle : **sandboxes** avec droits dérivés du **type dagent** et du **projet**.
Exemples de **profils de policy** : lecture seule ; lecture + scripts locaux ; écriture bornée ; déploiement pprod / prod ; génération documentaire ; accès tickets ; accès base ; accès ONLYOFFICE.
**Pas de fallback implicite** non spécifié : refus ou erreur explicite selon les règles du projet.
## Couche de normalisation (registre agents)
Registre unifié des agents `ia_dev`, chacun exposé comme **objet standardisé** :
- identité, catégorie, **commandes déclenchantes**, permissions, environnements compatibles, mode dexécution, outils requis, **politiques OpenShell**, formats dentrée/sortie, stratégies de rejet (pas de fallback silencieux), journalisation, possibilité dappeler dautres agents.
Sans cette couche, lIDE reste dépendant de **conventions implicites** du dépôt.
## Agent gateway (adaptateur)
Ne pas brancher le dépôt `ia_dev` directement dans léditeur : passer par une **agent gateway** qui :
1. Charge le **registre**
2. **Valide** les permissions
3. **Résout** les dépendances
4. Ouvre la **sandbox OpenShell** adaptée
5. **Injecte** le contexte autorisé
6. **Lance** lagent
7. **Capture** les événements
8. **Uniformise** les sorties
9. **Publie** le flux vers léditeur
10. **Journalise**
11. Gère **rollbacks** et statuts
## Modules logiciels (découpage)
| Module | Responsabilité |
|--------|----------------|
| **editor-shell** | Éditeur texte léger, terminal, explorer **mode expert**, onglets, palette de commandes, timeline, UX |
| **agent-gateway** | Adaptateur uniforme UX ↔ `ia_dev` |
| **policy-runtime** | OpenShell, profils de policy, providers, sandboxes, journaux |
| **knowledge-services** | AnythingLLM, mémoire projet, index documentaire, routage RAG |
| **doc-services** | ONLYOFFICE, flux `present`, `write`, `sheet` |
Les **agents** restent le noyau opératoire ; les modules encadrent et exposent.
## UX — masquage des agents
Lutilisateur ne « choisit pas un agent » dans le flux nominal : il exprime une **intention** (`ask`, `fix`, …). Le **routeur** sélectionne lagent ou la chaîne dagents.
## Socle éditeur : Lapce
**Lapce** (open source, Rust, rendu natif / GPU) est le candidat retenu pour un **éditeur rapide et léger** avec agents, au lieu dun IDE historique très chargé. Positionnement aligné avec le rôle « coquille + orchestration + transparence contextuelle » décrit dans [ux-navigation-model.md](./ux-navigation-model.md).
## Taxonomie des droits
Les droits doivent être **nommés**, **vérifiables** et **traçables** (lien avec OpenShell et le registre dagents). Pas de contournement par défaut.
## Mémoire dexécution
Conserver une mémoire dexécution **exploitable** : rejouer, auditer, promouvoir une exécution réussie en **recette** versionnée.

116
docs/ux-navigation-model.md Normal file
View File

@ -0,0 +1,116 @@
# Modèle UX — au-delà de lexplorateur fichiers
## Renoncer à lexplorer classique
Renoncer à une vue fichiers / dossiers / explorateur **ne signifie pas** labsence de structure : cest une interface **orientée intention**, **contexte**, **flux dactions** et **artefacts**.
Si Git est peu visible en surface, si les **procédures** sont déterministes, si les **agents** savent installer, importer et développer des **outils génériques** avant dappeler lIA, et si lutilisateur travaille surtout via des commandes de haut niveau (`ask`, `fix`, `improve`, `deploy`, `ticket`, `present`, `write`, `sheet`, `extract`, `think adversarial`, etc.), lexplorer nest pas remplacé par « rien », mais par des **vues plus adaptées** au modèle.
## Ce que lexplorer faisait — et comment le redistribuer
| Besoin historique (explorer) | Remplacement ciblé |
|------------------------------|-------------------|
| Localiser physiquement les fichiers | Recherche, commandes, **mémoire projet**, points dentrée contextuels |
| Comprendre la structure du projet | Vues **sémantiques** : modules, services, tickets, environnements, procédures, agents, artefacts, documents |
| Agir sur des objets concrets | **Palette dintentions** + vues d**objets métier** |
Le bon niveau dabstraction devient :
1. Ce que je veux faire
2. Sur quel **objet logique**
3. Avec quels **droits**
4. Dans quel **contexte projet**
5. Avec quelle **procédure**
6. Avec quel **agent**
7. Avec quel **résultat attendu**
→ Plus proche dune **machine de travail orientée opérations** que dun éditeur de fichiers.
## Risques si lexplorer disparaît sans compensations
1. **Perte de repère spatial**
2. **Difficulté dinspection libre**
3. **Fragilité agentique** si le graphe sémantique (agents, index, résumés, outils, procédures) est **incomplet** — labsence dexplorer est alors vécue comme une **privation**, pas comme une abstraction supérieure
4. **Effet boîte noire**
## Compensations obligatoires
### Palette daccès universelle (« go to anything »)
Trouver et ouvrir immédiatement, par nom, alias, rôle, description, historique, proximité contextuelle, **permissions** :
- fichier, module, service, fonction, procédure, agent, ticket, environnement, document, support de présentation, feuille, job, log, artefact généré, commande.
### Vue des objets logiques
À la place dune arborescence de fichiers : **services**, **modules**, **environnements**, **tickets**, **bases**, **agents**, **recipes**, **tools**, **documents**, **supports**, **jobs**, **déploiements**, **artefacts**.
Lutilisateur voit en permanence **sur quoi il travaille** : projet courant, tâche courante, commande active, agents impliqués, artefacts produits, documents de référence, état stable disponible, environnement concerné.
### Recherche structurée (au-delà du grep fichiers)
Capacité de chercher dans : code, **symboles**, recettes, outils, **historiques de session**, tickets, documents, logs, artefacts ONLYOFFICE, sorties dagents, **mémoire AnythingLLM**.
### Vue artefacts
Artefacts **récents** et **liés au contexte courant** : scripts, documents, feuilles, présentations, tickets, logs, plans, sorties diverses.
### Vue timeline / stream
Ce nest pas la liste des fichiers, mais les **actions** : lancé, lu, généré, échoué, disponible, repris.
## Types dobjets ouvrables
- **Texte** : source, config, script, note, document texte
- **Logique** : service, module, fonction, procédure, agent, ticket
- **Exécution** : job, déploiement, test, lint, run agentique, terminal de tâche
- **Artefact** : présentation, document, feuille, rapport, résumé, sortie de recette
Navigation **sans penser « répertoire »**, en pensant **« objet »**.
## Arborescence vs graphe
Lexplorer repose sur un **arbre**. Le système cible un **graphe** : ticket → agents → recettes → scripts → artefacts → projet → environnements → procédures → documents → support → ticket, etc.
Rendre visible : structure logique, objets importants, actions disponibles, **relations**, état courant, artefacts récents modifiés, sorties dagents, points dentrée, chemins de reprise.
## Conditions de réussite
1. **Indexation solide** : fichiers, symboles, modules, services, tickets, scripts, recettes, documents, artefacts, historiques
2. **Palette universelle** exceptionnelle
3. **Recherche** plein texte + sémantique
4. **Vues contexte + timeline** fiables
5. **Mémoire projet** fiable (AnythingLLM par projet + synchro)
6. **Commandes principales** réellement suffisantes au quotidien
7. **Mode expert / secours** pour accéder au niveau bas (y compris vue fichiers brute) si labstraction haute échoue
**Ne pas supprimer totalement lexplorer du produit** : le retirer de linterface **normale**, mais garder un accès discret / désactivable par défaut si indexation, relations ou agents déraillent.
## Trois niveaux proposés
| Niveau | Rôle |
|--------|------|
| **Principal** | Pas dexplorer classique ; commandes, recherche, contexte, timeline, objets logiques, artefacts |
| **Secondaire** | Vue « structure » non arborescente : services, modules, objets, procédures |
| **Expert** | Accès secours à la structure brute (fichiers / répertoires), discret, éventuellement désactivé par défaut |
## Grammaire des commandes
Plus lexplorer disparaît de la surface, plus les commandes doivent être **rigoureuses** :
- `ask` — interrogation du graphe de connaissances et dobjets
- `fix` — réparation guidée (tests), sans obligation de « trouver le fichier » manuellement
- `improve` — optimisation sur objet logique ou contexte courant
- `deploy` — action sur **environnement** et **procédure**, pas sur un répertoire
- `ticket` — entrée de navigation métier
- `present`, `write`, `sheet` — générateurs dartefacts liés au contexte logique du projet
- `extract` — extraction structurée depuis sources / documents / contexte
- `think adversarial` — revue ou stress test (sécurité, hypothèses, angles de défaillance) sur lobjet ou le livrable courant
Synthèse : *pas dexplorer comme surface principale ; navigation par intentions, recherche, objets logiques, timeline et artefacts ; accès brut réservé au mode expert.*
## Chaîne UX cible (rappel)
Éditeur → **orchestrateur UX****runtime sécurisé** → agents `ia_dev` → sous-agents → (préparation / scripts / tools) → IA avec éléments demandés → réponse intégrée à lIDE.
Lexplorer est remplacé par **mieux** : palette universelle, navigation par objets, vue contexte, timeline, recherche puissante, vue artefacts, niveau expert de secours.

39
install-anythingllm-docker.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash
# Install / start AnythingLLM on Ubuntu via Docker (official image mintplexlabs/anythingllm).
# Docs: https://docs.anythingllm.com/installation-docker/local-docker
# UI: http://localhost:3001
#
# Optional env:
# STORAGE_LOCATION default: $HOME/anythingllm
# HOST_PORT default: 3001
# Usage: ./install-anythingllm-docker.sh
set -euo pipefail
STORAGE_LOCATION="${STORAGE_LOCATION:-${HOME}/anythingllm}"
HOST_PORT="${HOST_PORT:-3001}"
IMAGE="${ANYTHINGLLM_IMAGE:-mintplexlabs/anythingllm}"
CONTAINER_NAME="${ANYTHINGLLM_CONTAINER_NAME:-anythingllm}"
mkdir -p "${STORAGE_LOCATION}"
touch "${STORAGE_LOCATION}/.env"
docker pull "${IMAGE}"
if docker ps -a --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then
docker rm -f "${CONTAINER_NAME}"
fi
docker run -d \
-p "${HOST_PORT}:3001" \
--name "${CONTAINER_NAME}" \
--cap-add SYS_ADMIN \
--add-host=host.docker.internal:host-gateway \
-v "${STORAGE_LOCATION}:/app/server/storage" \
-v "${STORAGE_LOCATION}/.env:/app/server/.env" \
-e STORAGE_DIR="/app/server/storage" \
"${IMAGE}"
echo "AnythingLLM is starting. Open http://localhost:${HOST_PORT}"
echo "Storage: ${STORAGE_LOCATION}"

198
installer.sh Executable file
View File

@ -0,0 +1,198 @@
#!/bin/sh
# This script installs AnythingLLMDesktop on Linux.
# On systems with AppArmor enabled, the AppImage needs to also create a userspace
# apparmor profile so that the AppImage can be run without SUID requirements due to root chromium ownership.
#
# Todo: Detect the current location of the AppImage so that we can update the application
# in-place without the user needed to manually move the application to the new location.
# This is also useful so that the apparmor location is always correct if the user edits it.
set -eu
status() { echo "$*" >&2; }
error() { echo "ERROR $*"; exit 1; }
warning() { echo "WARNING: $*"; }
# Detect AppArmor major version so we generate compatible profile syntax.
# AppArmor 4.x (Ubuntu 24.04+) supports abi declarations and userns rules;
# older versions (Ubuntu 20.04/22.04) need classic syntax only.
get_apparmor_major_version() {
if command -v apparmor_parser >/dev/null 2>&1; then
apparmor_parser --version 2>/dev/null | grep -oE '[0-9]+' | head -1
else
echo "0"
fi
}
# Create an AppArmor profile for AnythingLLMDesktop for systems with AppArmor enabled
# https://askubuntu.com/questions/1512287/obsidian-appimage-the-suid-sandbox-helper-binary-was-found-but-is-not-configu/1528215#1528215
create_apparmor_profile() {
status "Checking for sudo privileges..."
sudo -v
if [ $? -ne 0 ]; then
error "Failed to get sudo privileges! Aborting..."
exit 1
fi
AA_MAJOR=$(get_apparmor_major_version)
status "Creating AppArmor profile for AnythingLLM (AppArmor version ${AA_MAJOR}.x detected)..."
if [ "${AA_MAJOR}" -ge 4 ] 2>/dev/null; then
APP_ARMOR_CONTENT=$(cat <<'EOF'
# AnythingLLMDesktop AppArmor profile (4.x syntax)
abi <abi/4.0>,
include <tunables/global>
profile anythingllmdesktop /**/AnythingLLMDesktop.AppImage flags=(unconfined) {
userns,
}
EOF
)
else
APP_ARMOR_CONTENT=$(cat <<'EOF'
# AnythingLLMDesktop AppArmor profile (classic syntax for AppArmor 2.x/3.x)
#include <tunables/global>
profile anythingllmdesktop /**/AnythingLLMDesktop.AppImage flags=(unconfined) {
}
EOF
)
fi
echo "$APP_ARMOR_CONTENT" | sudo tee /etc/apparmor.d/anythingllmdesktop > /dev/null
status "Reloading AppArmor service..."
if sudo apparmor_parser -r /etc/apparmor.d/anythingllmdesktop 2>/dev/null; then
status "AppArmor profile created - you can now run AnythingLLMDesktop without SUID requirements."
elif sudo systemctl reload apparmor.service 2>/dev/null; then
status "AppArmor profile created - you can now run AnythingLLMDesktop without SUID requirements."
else
warning "AppArmor reload failed. The profile was written to /etc/apparmor.d/anythingllmdesktop"
warning "but could not be loaded. You may need to reboot or run:"
warning " sudo apparmor_parser -r /etc/apparmor.d/anythingllmdesktop"
warning "If issues persist, you can disable the profile for this app only:"
warning " sudo ln -sf /etc/apparmor.d/anythingllmdesktop /etc/apparmor.d/disable/"
warning " sudo systemctl reload apparmor"
fi
}
check_to_create_apparmor_profile() {
# Check if the system has AppArmor enabled
if [ -f /sys/kernel/security/apparmor/profiles ]; then
if ! [ -f /etc/apparmor.d/anythingllmdesktop ]; then
status "AppArmor is enabled on this system."
status "\e[31m[Warning]\e[0m You will get an error about SUID permission issues when running the AppImage without creating an AppArmor profile."
status "This requires sudo privileges. If you are unsure, you can create an AppArmor profile manually."
read -p "Do you want to auto-create an AppArmor profile for AnythingLLM now? (y/n): " create_apparmor
case "$create_apparmor" in [yY]) create_apparmor="y" ;; esac
if [ "$create_apparmor" = "y" ]; then
create_apparmor_profile
else
status "AppArmor is enabled on this system."
status "AppArmor profile creation skipped. You may not be able to run AnythingLLMDesktop without it."
fi
else
status "AppArmor profile already exists."
read -p "Do you want to overwrite it with the latest version? (y/n): " overwrite_apparmor
case "$overwrite_apparmor" in [yY]) overwrite_apparmor="y" ;; esac
if [ "$overwrite_apparmor" = "y" ]; then
create_apparmor_profile
fi
fi
else
status "AppArmor could not be automatically detected or does not exist. If you get an SUID error on startup, you may need to create an AppArmor profile for AnythingLLMDesktop.AppImage manually."
fi
}
check_or_create_desktop_profile() {
if ! [ -f $HOME/.local/share/applications/anythingllmdesktop.desktop ]; then
status "Desktop profile not found. Creating..."
# Default Exec command
EXEC_CMD="$INSTALL_DIR/AnythingLLMDesktop.AppImage"
# Check for Wayland + KDE specifically
# We check XDG_SESSION_TYPE for "wayland"
# We check XDG_CURRENT_DESKTOP for "KDE" (handles "KDE", "KDE-Plasma", etc)
# We use ':-' to safely handle unbound variables in 'set -u' mode
if [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
case "${XDG_CURRENT_DESKTOP:-}" in
*"KDE"*)
status "Detected KDE Plasma on Wayland. Adding specific flags for IME support."
EXEC_CMD="$INSTALL_DIR/AnythingLLMDesktop.AppImage --enable-features=UseOzonePlatform --ozone-platform=wayland --enable-wayland-ime"
;;
esac
fi
DESKTOP_CONTENT=$(cat <<EOF
[Desktop Entry]
StartupWMClass=anythingllm-desktop
Type=Application
Name=AnythingLLM Desktop
Exec=$EXEC_CMD
Icon=$HOME/.config/anythingllm-desktop/storage/icon.png
Categories=Utility;
EOF
)
mkdir -p $HOME/.local/share/applications
echo "$DESKTOP_CONTENT" | tee $HOME/.local/share/applications/anythingllmdesktop.desktop > /dev/null
status "Desktop profile created!"
fi
}
arch=$(uname -m)
[ "$(uname -s)" = "Linux" ] || error 'This script is intended to run on Linux only.'
if [ "$(id -u)" -eq 0 ]; then
status "This script should not be run as root. Please run it as a regular user."
exit 1
fi
# Allow custom installation directory via ANYTHING_LLM_INSTALL_DIR environment variable
# Defaults to $HOME if not set
INSTALL_DIR="${ANYTHING_LLM_INSTALL_DIR:-$HOME}"
status "#########################################################"
status " Welcome to the AnythingLLM Desktop Installer"
status " by Mintplex Labs Inc (team@mintplexlabs.com)"
status " Architecture: $arch"
status " Install Directory: $INSTALL_DIR"
status "#########################################################"
if [ "$arch" = "arm64" ] || [ "$arch" = "aarch64" ]; then
APPIMAGE_URL="https://cdn.anythingllm.com/latest/AnythingLLMDesktop-Arm64.AppImage"
else
APPIMAGE_URL="https://cdn.anythingllm.com/latest/AnythingLLMDesktop.AppImage"
fi
APPIMAGE_FILE="AnythingLLMDesktop.AppImage"
mkdir -p "$INSTALL_DIR"
SHOULD_DOWNLOAD="true"
if [ -f "$INSTALL_DIR/$APPIMAGE_FILE" ]; then
status "Existing installation found at $INSTALL_DIR/$APPIMAGE_FILE"
read -p "Do you want to re-download and overwrite it? (y/n): " overwrite
case "$overwrite" in [yY]) ;; *) SHOULD_DOWNLOAD="false" ;; esac
fi
if [ "$SHOULD_DOWNLOAD" = "true" ]; then
status "Downloading AnythingLLM Desktop..."
curl --fail --show-error --location --progress-bar -o "$INSTALL_DIR/$APPIMAGE_FILE" "$APPIMAGE_URL"
chmod +x "$INSTALL_DIR/$APPIMAGE_FILE"
fi
status "AnythingLLM Desktop is ready to run!"
status "$INSTALL_DIR/$APPIMAGE_FILE to start AnythingLLMDesktop"
status "\e[36mHeads up!\e[0m You can rerun this installer anytime to get the latest version of AnythingLLM without effecting your existing data."
status "Documentation: https://docs.anythingllm.com"
status "Issues: https://github.com/Mintplex-Labs/anything-llm"
status "\e[36mThanks for using AnythingLLM!\e[0m\n\n"
status "Next, we will create a desktop profile and AppArmor profile for AnythingLLMDesktop."
status "This is required for the AppImage to be able to run without SUID requirements."
status "You can manually create these profiles if you prefer."
check_or_create_desktop_profile
check_to_create_apparmor_profile
read -p "Do you want to start AnythingLLMDesktop now? (y/n): " start
case "$start" in [yY]) start="y" ;; esac
if [ "$start" = "y" ]; then
"$INSTALL_DIR/$APPIMAGE_FILE"
fi