Skip to content

Commit a3683ba

Browse files
authored
Merge pull request #4 from DrJLabs/feat/profile-instance-management
feat: add registry-backed instance management previews
2 parents f7fa57e + b2383cc commit a3683ba

29 files changed

Lines changed: 2871 additions & 450 deletions

DOCKER.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020

2121
The compose stack now mounts the whole `./prompts` tree into `/app/prompts` and each service keeps its own runtime prompt config file under `/data`.
2222

23+
Registry-backed management metadata now also lives in:
24+
25+
- `config/profiles/*.yaml`
26+
- `config/instances/*.yaml`
27+
28+
Those registry files are used for validation, instance listing, and runtime previews.
29+
They do not replace the live prompt manager or the live `docker-compose.yml` entrypoint in this phase.
30+
2331
Default runtime prompt selection:
2432

2533
- `chatmock` uses `${CHATMOCK_PROMPT_DIR:-/app/prompts/bare}`
@@ -72,6 +80,24 @@ curl -sS -X POST http://127.0.0.1:8000/admin/prompts/reload \
7280
-H "X-ChatMock-Admin-Token: $CHATMOCK_ADMIN_TOKEN" | jq .
7381
```
7482

83+
## Instance registry inspection
84+
85+
Registry-backed read/preview controls are also exposed locally:
86+
87+
- `GET /admin/profiles`
88+
- `GET /admin/instances`
89+
- `GET /admin/instances/<instance_id>/preview`
90+
91+
CLI equivalents:
92+
93+
```bash
94+
chatmock instances list
95+
chatmock instances validate
96+
chatmock instances preview chatmock
97+
```
98+
99+
These controls are intended to give the current GUI or a future replacement UI a stable backend contract before any lifecycle/provisioning work is added.
100+
75101
## Isolated test stack
76102

77103
Use the override file to bring up a disposable stack on separate ports without touching the live services or their `/data` volume.

chatmock.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

3+
import sys
4+
35
from chatmock.cli import main
46

57
if __name__ == "__main__":
6-
main()
7-
8+
sys.exit(main())

chatmock/app.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from .config import get_prompt_manager
1212
from .http import build_cors_headers
13+
from .instance_service import build_instance_service
1314
from .routes_openai import openai_bp
1415
from .routes_ollama import ollama_bp
1516
from .websocket_routes import register_websocket_routes
@@ -49,6 +50,7 @@ def create_app(
4950
DEFAULT_WEB_SEARCH=bool(default_web_search),
5051
INJECT_DEFAULT_INSTRUCTIONS=bool(inject_default_instructions),
5152
PROMPT_MANAGER=prompt_manager,
53+
INSTANCE_SERVICE=None,
5254
ADMIN_TOKEN=(
5355
admin_token
5456
if isinstance(admin_token, str) and admin_token
@@ -107,6 +109,16 @@ def _is_in_trusted_ranges(value: str | None) -> bool:
107109
return jsonify({"error": {"message": "Invalid admin token"}}), 403
108110
return None
109111

112+
def _get_instance_service():
113+
service = app.config.get("INSTANCE_SERVICE")
114+
if service is None:
115+
service = build_instance_service()
116+
app.config["INSTANCE_SERVICE"] = service
117+
return service
118+
119+
def _registry_error(exc: Exception):
120+
return jsonify({"error": {"message": str(exc)}}), 400
121+
110122
@app.get("/admin/prompts")
111123
def admin_prompts_state():
112124
denied = _require_local_admin()
@@ -142,6 +154,43 @@ def admin_prompts_config():
142154
return jsonify({"error": {"message": str(exc)}}), 400
143155
return jsonify(prompt_manager.as_dict())
144156

157+
@app.get("/admin/profiles")
158+
def admin_profiles():
159+
denied = _require_local_admin()
160+
if denied is not None:
161+
return denied
162+
try:
163+
service = _get_instance_service()
164+
except (FileNotFoundError, OSError, ValueError) as exc:
165+
return _registry_error(exc)
166+
return jsonify({"profiles": service.list_profiles()})
167+
168+
@app.get("/admin/instances")
169+
def admin_instances():
170+
denied = _require_local_admin()
171+
if denied is not None:
172+
return denied
173+
try:
174+
service = _get_instance_service()
175+
except (FileNotFoundError, OSError, ValueError) as exc:
176+
return _registry_error(exc)
177+
return jsonify({"instances": service.list_instances()})
178+
179+
@app.get("/admin/instances/<instance_id>/preview")
180+
def admin_instance_preview(instance_id: str):
181+
denied = _require_local_admin()
182+
if denied is not None:
183+
return denied
184+
try:
185+
service = _get_instance_service()
186+
except (FileNotFoundError, OSError, ValueError) as exc:
187+
return _registry_error(exc)
188+
try:
189+
preview = service.render_instance_preview(instance_id)
190+
except ValueError as exc:
191+
return jsonify({"error": {"message": str(exc)}}), 404
192+
return jsonify(preview)
193+
145194
@app.after_request
146195
def _cors(resp):
147196
for k, v in build_cors_headers().items():
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
id: chatmock-clawmem
2+
label: ChatMock ClawMem
3+
profile_id: clawmem
4+
bind_host: 127.0.0.1
5+
port: 8001
6+
runtime: docker_compose
7+
prompt_config_path: /data/prompt-config-chatmock-clawmem.json
8+
state_group: shared-auth-default
9+
compose_service_name: chatmock-clawmem
10+
container_name: chatmock-clawmem
11+
env_prefix: CHATMOCK_CLAWMEM
12+
env_overrides: {}
13+
healthcheck:
14+
path: /health
15+
ui:
16+
order: 20
17+
mutable_fields:
18+
- profile_id
19+
- port
20+
enabled: true
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
id: chatmock
2+
label: ChatMock
3+
profile_id: bare
4+
bind_host: 127.0.0.1
5+
port: 8000
6+
runtime: docker_compose
7+
prompt_config_path: /data/prompt-config-chatmock.json
8+
state_group: shared-auth-default
9+
compose_service_name: chatmock
10+
container_name: chatmock
11+
env_prefix: CHATMOCK
12+
env_overrides: {}
13+
healthcheck:
14+
path: /health
15+
ui:
16+
order: 10
17+
mutable_fields:
18+
- profile_id
19+
- port
20+
enabled: true
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
id: bare
2+
label: Bare
3+
description: Default low-opinion prompt set for the main ChatMock service
4+
prompt_dir: chatmock/bundled_prompts/bare
5+
base_prompt_file: prompt.md
6+
codex_prompt_file: prompt_gpt5_codex.md
7+
runtime_defaults:
8+
inject_default_instructions: true
9+
ui:
10+
order: 10
11+
editable: true
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
id: clawmem
2+
label: ClawMem
3+
description: ClawMem-specific prompt set for the secondary managed service
4+
prompt_dir: chatmock/bundled_prompts/clawmem
5+
base_prompt_file: prompt.md
6+
codex_prompt_file: prompt_gpt5_codex.md
7+
runtime_defaults:
8+
inject_default_instructions: true
9+
ui:
10+
order: 20
11+
editable: true
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Follow the developer and user instructions contained in the input.
2+
When calling tools, you must strictly match the provided tool schema.
3+
Do not call a tool with empty arguments unless the schema explicitly allows no arguments.
4+
Always include every required argument before making the tool call.
5+
If a tool call returns a schema error, inspect the schema and try again with corrected arguments.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Follow the developer and user instructions contained in the input.
2+
When calling tools, you must strictly match the provided tool schema.
3+
Do not call a tool with empty arguments unless the schema explicitly allows no arguments.
4+
Always include every required argument before making the tool call.
5+
If a tool call returns a schema error, inspect the schema and try again with corrected arguments.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
You are a structured memory-enrichment model for ClawMem.
2+
3+
Your outputs feed a long-lived memory system. Precision, consistency, and schema discipline matter more than creativity or recall.
4+
5+
You may be asked to do one of four tasks:
6+
1. construct a memory note
7+
2. extract named entities
8+
3. classify document-to-document relations
9+
4. decide whether a memory should evolve
10+
11+
Global rules:
12+
- Follow the task prompt exactly.
13+
- If the task asks for JSON, return valid JSON only.
14+
- Do not add prose, markdown fences, headings, or explanations outside the requested JSON.
15+
- Never copy placeholder examples from the prompt.
16+
- Prefer omission over invention.
17+
- If uncertain, return fewer items.
18+
- Be conservative, stable, and repeatable.
19+
20+
Schema discipline:
21+
- Use exactly the requested keys and value types.
22+
- Do not add extra keys.
23+
- Do not rename keys.
24+
- Do not emit partial JSON.
25+
- If the best answer is "nothing," still return valid empty JSON in the requested schema.

0 commit comments

Comments
 (0)