refactor!: rename omos to Corentic Package Manager (CPM)

A CPM package is an agent package consisting of an APM manifest plus a
team configuration (team-profile.yaml). The manager translates such a
package into the native config of a target harness. First target:
oh-my-opencode-slim; oh-my-pi, codex, claude and copilot are planned.

- omos/ -> corentic-package-manager/, cpm.py as CLI entry point
- new commands: cpm init [--fill] and cpm setup (guided flow with
  interactive model selection from opencode.json(c))
- schema field omos_agent -> harness-neutral runtime_agent
- user mapping moved to ~/.config/cpm/model-mapping.yaml
- provenance suffix .cpm-provenance.json
- skill renamed to cpm-setup
This commit is contained in:
Tobias J. Endres 2026-08-23 17:26:28 +02:00
parent b897bb4b17
commit 2af88b6493
9 changed files with 89 additions and 69 deletions

View file

@ -1,31 +1,40 @@
# omos
# Corentic Package Manager (CPM)
Adapter zwischen APM-Packages mit Team-Profil und [oh-my-opencode-slim](https://github.com/alvinunreal/oh-my-opencode-slim).
Ein **CPM-Package** ist ein Agent-Package bestehend aus einem [APM](https://microsoft.github.io/apm/)-Manifest plus Team-Konfiguration (`team-profile.yaml`). Der Corentic Package Manager übersetzt dieses Package in die native Konfiguration eines Ziel-Harnesses.
`omos` liest eine `team-profile.yaml` aus einem APM-Package, löst abstrakte Modellklassen gegen deine lokale Mapping-Tabelle auf und generiert ein namespacetes oh-my-opencode-slim-Preset. Deterministisch `omos` rät nicht.
Übersetzungsziele:
| Ziel-Harness | Status |
|---|---|
| [oh-my-opencode-slim](https://ohmyopencodeslim.com/) | ✅ implementiert |
| oh-my-pi | geplant |
| Codex / Claude / Copilot | Vision |
Deterministisch der CPM rät nicht. Er nimmt keine Verfügbarkeit an und wählt keine Modelle automatisch aus.
```
APM-Package Nutzer Runtime
team-profile.yaml + model-mapping.yaml → omos render → .opencode/
(Rollen, Modell- (Modellklasse → oh-my-opencode-slim.json
klassen, MCPs/Skills) konkrete Modell-ID)
CPM-Package Nutzer Runtime
apm.yml + + model-mapping.yaml → cpm render → .opencode/
team-profile.yaml (Modellklasse → oh-my-opencode-slim.json
(Rollen, Modell- konkrete Modell-ID) (oder künftig: natives
klassen, MCPs/Skills) Config eines anderen Harness)
```
## Voraussetzungen
- Python 3.10+ mit PyYAML (`pip install pyyaml`)
- OpenCode mit installiertem Plugin [oh-my-opencode-slim](https://ohmyopencodeslim.com/)
- Ein APM-Package mit `team-profile.yaml`
- OpenCode mit installiertem Plugin [oh-my-opencode-slim](https://github.com/alvinunreal/oh-my-opencode-slim)
- Ein CPM-Package mit `team-profile.yaml`
## Schnellstart
```bash
# 1. Modell-Mapping anlegen interaktiv, mit Auswahl aus deinen opencode-Modellen
python3 omos.py init --fill
python3 cpm.py init --fill
# 2. Geführt: Team-Profil lesen, Mapping prüfen/auffüllen, rendern
cd <projekt>
python3 /pfad/zu/omos.py setup --package /pfad/zum/package
python3 /pfad/zu/cpm.py setup --package /pfad/zum/package
# 3. Aktivieren
opencode # Projekt-Config wird geladen
@ -37,16 +46,16 @@ Alternativ manuell:
```bash
# 1. Modell-Mapping einmalig anlegen
mkdir -p ~/.config/apm-team
cp examples/model-mapping.yaml ~/.config/apm-team/model-mapping.yaml
$EDITOR ~/.config/apm-team/model-mapping.yaml # an eigene Modelle anpassen
mkdir -p ~/.config/cpm
cp examples/model-mapping.yaml ~/.config/cpm/model-mapping.yaml
$EDITOR ~/.config/cpm/model-mapping.yaml # an eigene Modelle anpassen
# 2. Validieren (Dry-Run)
python3 omos.py check --package examples/package
python3 cpm.py check --package examples/package
# 3. Rendern
cd <projekt>
python3 /pfad/zu/omos.py render --package /pfad/zum/package
python3 /pfad/zu/cpm.py render --package /pfad/zum/package
```
## Die drei Dateien
@ -54,34 +63,34 @@ python3 /pfad/zu/omos.py render --package /pfad/zum/package
| Datei | Gehört | Zweck | Manuell editieren? |
|---|---|---|---|
| `team-profile.yaml` | Package-Autor | Rollen, Modellklassen, MCP-/Skill-Allowlists pro Rolle | Ja (Autor) |
| `~/.config/apm-team/model-mapping.yaml` | Nutzer | Modellklasse → konkrete Modell-ID (+ optional variant/temperature) | Ja (Nutzer) |
| `.opencode/oh-my-opencode-slim.json` | generiert | OMOS-Preset mit konkreten Modell-IDs | **Nein** immer neu rendern |
| `~/.config/cpm/model-mapping.yaml` | Nutzer | Modellklasse → konkrete Modell-ID (+ optional variant/temperature) | Ja (Nutzer) |
| `.opencode/oh-my-opencode-slim.json` | generiert | Preset mit konkreten Modell-IDs | **Nein** immer neu rendern |
Dazu eine Provenance-Datei `.opencode/oh-my-opencode-slim.omos-provenance.json`, die dokumentiert, welche Rolle welches Modell erhalten hat.
Dazu eine Provenance-Datei `.opencode/oh-my-opencode-slim.cpm-provenance.json`, die dokumentiert, welche Rolle welches Modell erhalten hat.
## Kommandoreferenz
```bash
python3 omos.py init [--mapping FILE] [--fill] # Mapping anlegen/füllen
python3 omos.py setup --package DIR [--mapping F] ... # geführter Ablauf
python3 omos.py render --package DIR [--mapping F] [--output F] [--dry-run]
python3 omos.py check --package DIR [--mapping F] # Dry-Run-Validierung
python3 cpm.py init [--mapping FILE] [--fill] # Mapping anlegen/füllen
python3 cpm.py setup --package DIR [--mapping F] ... # geführter Ablauf
python3 cpm.py render --package DIR [--mapping F] [--output F] [--dry-run]
python3 cpm.py check --package DIR [--mapping F] # Dry-Run-Validierung
```
### `init` Mapping anlegen
Erstellt `~/.config/apm-team/model-mapping.yaml` (falls nicht vorhanden). Mit `--fill` werden alle `PLACEHOLDER`-Klassen interaktiv abgefragt: `omos` listet alle Modelle aus deiner `opencode.json(c)` auf, du wählst per Nummer oder gibst eine Modell-ID manuell ein.
Erstellt `~/.config/cpm/model-mapping.yaml` (falls nicht vorhanden). Mit `--fill` werden alle `PLACEHOLDER`-Klassen interaktiv abgefragt: der CPM listet alle Modelle aus deiner `opencode.json(c)` auf, du wählst per Nummer oder gibst eine Modell-ID manuell ein.
### `setup` Geführter Ablauf
Der Ein-Kommando-Weg: zeigt das Team-Profil verständlich an, legt fehlendes Mapping an, fragt fehlende Modellklassen interaktiv ab (gleiche Auswahl wie `init --fill`), rendert und gibt die Aktivierungsschritte aus. Entspricht dem ResolveValidateRender-Ablauf.
Der Ein-Kommando-Weg: zeigt das Team-Profil verständlich an, legt fehlendes Mapping an, fragt fehlende Modellklassen interaktiv ab (gleiche Auswahl wie `init --fill`), rendert und gibt die Aktivierungsschritte aus.
### `render` / `check`
| Option | Default | Bedeutung |
|---|---|---|
| `--package` | `.` | APM-Package-Verzeichnis mit `team-profile.yaml` |
| `--mapping` | `~/.config/apm-team/model-mapping.yaml` | Lokale Mapping-Tabelle |
| `--package` | `.` | CPM-Package-Verzeichnis mit `team-profile.yaml` |
| `--mapping` | `~/.config/cpm/model-mapping.yaml` | Lokale Mapping-Tabelle |
| `--output` | `<package>/.opencode/oh-my-opencode-slim.json` | Zieldatei |
| `--team-file` | `team-profile.yaml` (alternativ `team.yaml`) | Alternativer Profilname |
@ -97,7 +106,7 @@ description: ...
roles:
- id: researcher # fachliche Rolle
purpose: ... # wird zu Prompt/Description für Custom Agents
omos_agent: librarian # optional: OMOS-Builtin oder 'custom'
runtime_agent: librarian # optional: Harness-Builtin oder 'custom'
# (Default: role-id als Custom Agent)
model_class: fast-research # Pflicht, muss im Mapping existieren
capabilities:
@ -105,7 +114,7 @@ roles:
skills: [job-application] # Skill-Allowlist ([] = keine)
```
Erkannte OMOS-Builtins: `orchestrator`, `oracle`, `librarian`, `explorer`, `fixer`, `designer`, `council`, `observer`. Alles andere (oder `omos_agent: custom`) erzeugt einen Custom Agent inklusive `prompt` und `orchestratorPrompt` aus dem `purpose`-Feld.
Das Feld `runtime_agent` ist bewusst harness-neutral benannt: Der Adapter entscheidet, wie die Rolle im Ziel-Harness repräsentiert wird. Erkannte Builtins des oh-my-opencode-slim-Adapters: `orchestrator`, `oracle`, `librarian`, `explorer`, `fixer`, `designer`, `council`, `observer`. Alles andere (oder `runtime_agent: custom`) erzeugt einen Custom Agent inklusive `prompt` und `orchestratorPrompt` aus dem `purpose`-Feld.
### Mapping-Formate
@ -120,25 +129,23 @@ model_classes:
Alle Zusatzfelder werden 1:1 in den Agent-Eintrag des Presets übernommen.
## Was omos prüft
## Was der CPM prüft
1. Team-Profil vorhanden, Schema bekannt, `id` und `roles` vorhanden
2. Jede `model_class` hat einen Mapping-Eintrag (sonst Fehler mit Lösungshinweis)
3. MCPs gegen `~/.config/opencode/opencode.json(c)` abgleichen (**Warnung**, kein Abbruch)
4. Rollen ohne MCPs/Skills → Hinweis
`omos` nimmt keine Verfügbarkeit an und wählt keine Modelle automatisch aus. Fehlt ein Mapping, bricht das Rendern mit konkreter Ursache ab.
## Walkthrough mit dem Beispiel-Package
```bash
cd omos/examples
cd corentic-package-manager/examples
# Trockenlauf: was würde generiert?
python3 ../omos.py check --package package --mapping model-mapping.yaml
python3 ../cpm.py check --package package --mapping model-mapping.yaml
# Rendern in das Beispiel-Projekt
python3 ../omos.py render --package package \
python3 ../cpm.py render --package package \
--mapping model-mapping.yaml \
--output package/.opencode/oh-my-opencode-slim.json
```
@ -164,6 +171,6 @@ cd package && opencode
## Grenzen (bewusst)
- `omos` startet keine Agenten und orchestriert nichts zur Laufzeit das macht oh-my-opencode-slim.
- Der CPM startet keine Agenten und orchestriert nichts zur Laufzeit das macht der Ziel-Harness.
- MCP-/Skill-Allowlists sind Capability Scoping, keine Sandbox. Irreversible Aktionen brauchen serverseitige Autorisierung + Human Approval.
- Die Modellverfügbarkeit wird gegen die opencode.jsonc-Namen geprüft, nicht per API-Healthcheck.

View file

@ -1,17 +1,26 @@
#!/usr/bin/env python3
"""omos Adapter zwischen APM-Team-Profilen und oh-my-opencode-slim.
"""cpm Corentic Package Manager.
Liest ein team-profile.yaml aus einem APM-Package, löst Modellklassen gegen
eine lokale Mapping-Tabelle auf und generiert ein namespacetes Preset für
oh-my-opencode-slim.
Ein CPM-Package ist ein Agent-Package bestehend aus einem APM-Manifest plus
Team-Konfiguration (team-profile.yaml). Der CPM übersetzt dieses Package in
die native Konfiguration eines Ziel-Harnesses. Erstes Übersetzungsziel:
oh-my-opencode-slim. Weitere Ziele (oh-my-pi, codex, claude, copilot) sind
geplant.
Liest ein team-profile.yaml, löst Modellklassen gegen eine lokale
Mapping-Tabelle auf und generiert ein namespacetes Preset für den
Ziel-Harness.
Kommandos:
omos render Team-Profil in OMOS-Preset übersetzen und schreiben
omos check Validieren ohne zu schreiben (Dry-Run)
cpm init Nutzer-Mapping anlegen (optional interaktiv füllen)
cpm setup Geführt: Profil lesen, Mapping auffüllen, rendern
cpm render Team-Profil in Harness-Preset übersetzen und schreiben
cpm check Validieren ohne zu schreiben (Dry-Run)
Beispiele:
python3 omos.py render --package examples/package --mapping ~/.config/apm-team/model-mapping.yaml
python3 omos.py check --package examples/package
python3 cpm.py setup --package examples/package
python3 cpm.py render --package examples/package --mapping ~/.config/cpm/model-mapping.yaml
python3 cpm.py check --package examples/package
"""
from __future__ import annotations
@ -25,7 +34,8 @@ from pathlib import Path
import yaml
# Eingebaute OMOS-Agenten. Alles andere wird als Custom Agent behandelt.
# Eingebaute Agenten des ersten Übersetzungsziels oh-my-opencode-slim.
# Alles andere wird als Custom Agent behandelt.
BUILTIN_AGENTS = {
"orchestrator",
"oracle",
@ -40,7 +50,7 @@ BUILTIN_AGENTS = {
DEFAULT_MAPPING_PATH = Path.home() / ".config" / "apm-team" / "model-mapping.yaml"
DEFAULT_TEAM_FILE = "team-profile.yaml"
DEFAULT_OUTPUT = Path(".opencode") / "oh-my-opencode-slim.json"
PROVENANCE_SUFFIX = ".omos-provenance.json"
PROVENANCE_SUFFIX = ".cpm-provenance.json"
SUPPORTED_SCHEMA = ("corentic.team-profile/v1", "acme.team-profile/v1")
@ -159,12 +169,12 @@ def build_preset(profile: dict, mapping: dict) -> tuple[dict, dict, list[str]]:
skills = list(capabilities.get("skills", []) or [])
purpose = str(role.get("purpose", "")).strip()
omos_agent = role.get("omos_agent", role_id)
if omos_agent == "custom":
runtime_agent = role.get("runtime_agent", role_id)
if runtime_agent == "custom":
# Explizit als Custom Agent markiert → rolleneigener Name.
agent_key = role_id
else:
agent_key = omos_agent
agent_key = runtime_agent
preset[agent_key] = {
**agent_fields,
@ -175,7 +185,7 @@ def build_preset(profile: dict, mapping: dict) -> tuple[dict, dict, list[str]]:
if agent_key in BUILTIN_AGENTS and agent_key != role_id:
preset[agent_key]["displayName"] = role_id
if agent_key not in BUILTIN_AGENTS or omos_agent == "custom":
if agent_key not in BUILTIN_AGENTS or runtime_agent == "custom":
if agent_key not in custom_agents:
prompt = (
purpose
@ -363,7 +373,7 @@ def cmd_render(args: argparse.Namespace) -> int:
"presetName": sanitize_preset_name(str(profile["id"])),
"roles": {
r.get("id"): {
"omosAgent": r.get("omos_agent", r.get("id")),
"runtimeAgent": r.get("runtime_agent", r.get("id")),
"modelClass": r.get("model_class"),
"resolvedModel": mapping[r["model_class"]],
"mcps": (r.get("capabilities", {}) or {}).get("mcps", []),
@ -468,7 +478,7 @@ def cmd_init(args: argparse.Namespace) -> int:
"bitte manuell ergänzen.")
print("\nNächster Schritt:")
print(f" omos.py check --package <package-dir> --mapping {mapping_path}")
print(f" cpm.py check --package <package-dir> --mapping {mapping_path}")
return 0
@ -523,11 +533,11 @@ def cmd_setup(args: argparse.Namespace) -> int:
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
prog="omos",
prog="cpm",
description=(
"Adapter zwischen APM-Team-Profilen und oh-my-opencode-slim. "
"Übersetzt deterministisch: Team-Profil + lokales Modell-Mapping "
"-> OMOS-Preset."
"-> Harness-Preset."
),
)
sub = parser.add_subparsers(dest="command", required=True)

View file

@ -1,7 +1,7 @@
# ~/.config/apm-team/model-mapping.yaml
# ~/.config/cpm/model-mapping.yaml
#
# Lokale Mapping-Tabelle des NUTZERS.
# Ordnet abstrakte Modellklassen aus Team-Profilen konkrete, lokal
# Ordnet abstrakte Modellklassen aus CPM-Packages (Team-Profile) konkrete, lokal
# verfügbare Modell-IDs zu. Einmal anlegen, gilt für alle Packages.
#
# Einfache Form: klasse: provider/modell-id

View file

@ -7,7 +7,8 @@
# - welche Teilmenge der MCPs und Skills jede Rolle verwenden darf.
#
# Der Nutzer löst die Modellklassen lokal auf (siehe model-mapping.yaml).
# Der Adapter omos generiert daraus ein oh-my-opencode-slim-Preset.
# Der CPM (Corentic Package Manager) übersetzt dieses Profil in die native
# Konfiguration eines Ziel-Harnesses aktuell: oh-my-opencode-slim.
schema: corentic.team-profile/v1
@ -26,7 +27,7 @@ roles:
- id: researcher
purpose: Sucht und bewertet Stellenausschreibungen gegen das Kandidatenprofil
omos_agent: librarian # nutzt OMOS-Builtin 'librarian' mit Alias
runtime_agent: librarian # nutzt oh-my-opencode-slim-Builtin 'librarian' mit Alias
model_class: fast-research
capabilities:
mcps: [websearch, webfetch, openviking]
@ -36,7 +37,7 @@ roles:
purpose: Erstellt auf Fakten basierende Anschreiben und Lebensläufe in ShareLaTeX.
Nutze nur freigegebene Profilfakten. Erfinde keine Erfahrung.
Reiche niemals selbstständig eine Bewerbung ein.
omos_agent: custom # eigener Custom Agent 'writer'
runtime_agent: custom # eigener Custom Agent 'writer'
model_class: strong-writing
capabilities:
mcps: [openviking, sharelatex]
@ -45,7 +46,7 @@ roles:
- id: checker
purpose: Prüft Fakten, Ton und Vollständigkeit gegen das Kandidatenprofil.
Jede Behauptung braucht eine belegbare Quelle.
omos_agent: oracle # nutzt OMOS-Builtin 'oracle' mit Alias
runtime_agent: oracle # nutzt oh-my-opencode-slim-Builtin 'oracle' mit Alias
model_class: high-reasoning
capabilities:
mcps: [openviking]
@ -54,7 +55,7 @@ roles:
- id: notifier
purpose: Informiert den Nutzer über fertige Entwürfe.
Versende niemals etwas ohne explizite Nutzerfreigabe.
omos_agent: custom # eigener Custom Agent 'notifier'
runtime_agent: custom # eigener Custom Agent 'notifier'
model_class: cheap-reliable
capabilities:
mcps: []

View file

@ -1,23 +1,23 @@
---
name: omos-setup
description: Activate when the user wants to set up, render, or troubleshoot an omos team from an APM package. Use for omos render, team-profile, model-mapping, oh-my-opencode-slim preset, fehlende Modellklassen.
name: cpm-setup
description: Activate when the user wants to set up, render, or troubleshoot a CPM package (APM package + team-profile). Use for cpm init, cpm setup, cpm render, team-profile, model-mapping, oh-my-opencode-slim preset, fehlende Modellklassen.
allowed-tools:
- "Bash(python3 omos/omos.py *)"
- "Bash(python3 corentic-package-manager/cpm.py *)"
- "Read"
- "Write"
- "Edit"
- "Glob"
---
# OMOS Setup Skill
# CPM Setup Skill
Führt den Nutzer durch: APM-Package mit Team-Profil → lokales Modell-Mapping → gerendertes oh-my-opencode-slim-Preset.
Führt den Nutzer durch: CPM-Package (APM-Manifest + Team-Profil) → lokales Modell-Mapping → gerendertes Harness-Preset (aktuell: oh-my-opencode-slim).
## Der Ablauf (ResolveValidateRender)
### 1. Team-Profil finden
Prüfe, ob eine `team-profile.yaml` existiert (Package-Root oder `omos/examples/team-profile.yaml`). Lies sie und fasse dem Nutzer zusammen:
Prüfe, ob eine `team-profile.yaml` existiert (Package-Root oder `corentic-package-manager/examples/package/team-profile.yaml`). Lies sie und fasse dem Nutzer zusammen:
```
Profil: acme.job-applications
@ -28,7 +28,7 @@ MCPs benötigt: openviking, sharelatex (+ websearch/webfetch als OpenCode-Native
### 2. Mapping prüfen
Prüfe `~/.config/apm-team/model-mapping.yaml`. Für **jede** im Profil verwendete Modellklasse muss ein Eintrag existieren.
Prüfe `~/.config/cpm/model-mapping.yaml`. Für **jede** im Profil verwendete Modellklasse muss ein Eintrag existieren.
Wenn eine Modellklasse fehlt, biete dem Nutzer konkrete Optionen an (verfügbare Modelle aus `~/.config/opencode/opencode.jsonc` auflisten):
@ -41,6 +41,8 @@ Für 'high-reasoning' ist kein Modell zugeordnet.
Nach Auswahl schreibe das Mapping und markiere optional `# selected_by: user`.
Alternativ die interaktiven Kommandos nutzen: `cpm init --fill` und `cpm setup`.
### 3. MCPs prüfen
Vergleiche die im Profil genannten MCPs mit der Sektion `mcp` in `~/.config/opencode/opencode.jsonc`. Fehlende dem Nutzer melden nicht stillschweigend ignorieren. Native OpenCode-Tools (`websearch`, `webfetch`) sind keine MCPs und brauchen keinen Eintrag.
@ -48,7 +50,7 @@ Vergleiche die im Profil genannten MCPs mit der Sektion `mcp` in `~/.config/open
### 4. Rendern
```bash
python3 omos/omos.py render --package <package-dir>
python3 corentic-package-manager/cpm.py render --package <package-dir>
```
Zeige die Ausgabe inklusive Warnungen. Die Datei `.opencode/oh-my-opencode-slim.json` ist generiert nicht manuell editieren.