> For the complete documentation index, see [llms.txt](https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/.spec_system/archive/sessions/phase40-session06-moa-save-endpoint/spec.md).

# Session Specification

**Session ID**: `phase40-session06-moa-save-endpoint` **Phase**: 40 - Claude OS v2.10.1 Semantic Port **Status**: Not Started **Created**: 2026-07-03 **Base Commit**: f76ac560d006164858a6e69c99094bc6443c456b

***

## 1. Session Overview

This session adds the admin-gated Ministry MoA preset save endpoint required before later Ministry builder and save UX sessions can persist generated presets. The endpoint lives in the existing Hermes admin bridge, uses the same loopback, Host-header, same-run token, explicit admin gate, body-size, schema-validation, safe-error, and redaction patterns as the completed command endpoint, and writes only the MoA preset/default fields in the local Hermes config.

The work is next because Session 03 delivered shared browser-visible output redaction, Session 04 added MoA chat override sending, and Session 05 proved the current endpoint registration, parser, and hook patterns for new admin bridge actions. Session 06 consumes those foundations by adding safe local YAML persistence without adding the Ministry builder UI.

The session deliberately avoids frontend YAML generation and visible save controls. It provides the backend, parser, hook, and test contracts that Sessions 14 and 15 can use when the Ministry product surface is built.

***

## 2. Objectives

1. Add POST `/__hermes_moa_save` to the Hermes admin bridge with the existing local-only admin control-plane gates.
2. Validate MoA preset payloads before any file read or write, including preset name, aggregator model, one to three reference models, bounded temperature, bounded `max_tokens`, and rejected unknown or oversized fields.
3. Safely read, back up, merge, dump, and atomically replace `config.yaml`, changing only `moa.presets[name]` and `moa.default_preset`.
4. Add typed admin parser and `useHermesAdmin` hook surface for later Ministry save UX, with duplicate-trigger prevention while a save is in flight.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase40-session03-shared-redaction-foundation` - Provides the shared bridge-output sanitizer required for safe browser-visible errors.
* [x] `phase40-session04-chat-overrides-and-runtime` - Provides MoA chat override conventions and provider/model validation context.
* [x] `phase40-session05-command-endpoint` - Provides the current admin endpoint registration, parser, hook, fixture, and gated mutation patterns.

### Required Tools Or Knowledge

* Bun 1.3.14 package/runtime baseline.
* Existing Hermes admin bridge owner in `scripts/lib/hermes-admin-bridge.ts`.
* Existing `js-yaml` `load` and `dump` dependency already imported by the admin bridge.
* Existing parser owner in `src/lib/hermes-admin-types.ts`.
* Existing admin hook owner in `src/hooks/use-hermes-admin.ts`.

### Environment Requirements

* Local checkout with dependencies installed or installable through `bun install`.
* No live Hermes installation or provider credentials required; tests should use temp Hermes homes, synthetic config files, and mocked bridge requests.

***

## 4. Scope

### In Scope (MVP)

* AI OS exposes POST `/__hermes_moa_save` from the existing Hermes admin bridge.
* The endpoint requires loopback, same-run token, and explicit `HERMES_DASHBOARD_ADMIN=1` because it writes local Hermes config.
* Payload validation accepts one preset name, one aggregator model config, and one to three reference model configs.
* Model configs accept provider, model, optional temperature from 0 to 2, and optional `max_tokens` from 1 to 200000.
* Unknown fields are rejected at the root payload, aggregator, and reference model levels before file reads or writes.
* Missing `config.yaml` returns a setup-required error without exposing raw private paths.
* Existing config is backed up before mutation; the response returns the preset name and backup filename label only.
* The YAML merge preserves all unrelated config keys and unrelated MoA presets.
* Admin types and `useHermesAdmin` expose a typed `savePreset` action for later Ministry save UX.

### Out Of Scope (Deferred)

* Ministry builder UI - Reason: Session 14 owns builder integration in Pantheon.
* Final save UX and analytics - Reason: Session 15 owns Ministry config, analytics, and direct save UX.
* Frontend YAML generation - Reason: this endpoint accepts typed JSON and owns structured YAML merge behavior.
* Writing any Hermes config key outside `moa.presets[name]` and `moa.default_preset` - Reason: the session objective is narrow MoA persistence, not general Hermes config editing.

***

## 5. Technical Approach

### Architecture

Add the endpoint in `scripts/lib/hermes-admin-bridge.ts` beside `/__hermes_cmd` and other admin write routes. Register `/__hermes_moa_save` in the bridge-local `ENDPOINTS` list so the existing `registerHermesAdminBridge()` middleware wiring continues to own route registration.

Keep request validation local to the admin bridge and reject malformed payloads before any filesystem access. Resolve the config path with the existing `resolveHermesHome(options)` helper plus `config.yaml`, read it through bounded text helpers, parse it with `js-yaml`, require an object root, then copy a backup file in the same directory before writing an atomic replacement through a temporary file and `rename()`.

The successful response should be small and browser-safe: `{ ok: true, preset, defaultPreset, backup }`, where `backup` is a filename label such as `config.yaml.aios-backup-YYYYMMDDHHMMSS`. Errors should reuse the existing controlled JSON error shape and add a `setup_required` error code for missing config. No response should include raw config paths, YAML contents, provider credentials, account auth paths, or local usernames.

### Design Patterns

* Boundary validation: Parse and validate request shape before reading or writing config.
* Parser-owned contracts: Add MoA save request/response types and parser in `src/lib/hermes-admin-types.ts` before exposing the hook action.
* Local control-plane defense in depth: Preserve loopback, Host-header, token, admin, method, body-size, schema, safe-error, and redaction gates.
* Transactional local write: Back up current config, write a temp file, then rename over `config.yaml` only after YAML dump succeeds.
* Narrow mutation surface: Merge only `moa.presets[name]` and `moa.default_preset`; preserve all unrelated config keys.

***

## 6. Deliverables

### Files To Create

| File | Purpose                                                     | Est. Lines |
| ---- | ----------------------------------------------------------- | ---------- |
| None | No new production source file is expected for this session. | 0          |

### Files To Modify

| File                                                                              | Changes                                                                                                                                                                                              | Est. Lines |
| --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `scripts/lib/hermes-admin-bridge.ts`                                              | Add MoA save types, payload validation, config path/read/backup/atomic write helpers, `/__hermes_moa_save` handler, endpoint registration, and safe setup/error response mapping.                    | \~300      |
| `scripts/lib/__tests__/hermes-admin-bridge.test.ts`                               | Add MoA save coverage for gates, validation, missing config, invalid YAML/root, backup creation, merge preservation, default preset update, no raw path leakage, and no writes for invalid payloads. | \~360      |
| `src/lib/hermes-admin-types.ts`                                                   | Add MoA save request/response contracts, `setup_required` error code support, and response parser.                                                                                                   | \~90       |
| `src/lib/__tests__/hermes-admin-types.test.ts`                                    | Add parser coverage for valid MoA save responses and malformed response rejection.                                                                                                                   | \~80       |
| `src/hooks/use-hermes-admin.ts`                                                   | Add `moa` admin action group with `savePreset`, mutation state, and duplicate-trigger prevention while in flight.                                                                                    | \~90       |
| `src/hooks/__tests__/use-hermes-admin.test.tsx`                                   | Add hook coverage for save payloads, disabled/token/offline states, parser failures, and duplicate in-flight prevention.                                                                             | \~130      |
| `src/components/hermes/__tests__/hermes-documents-gallery.test.tsx`               | Update admin hook fixture shape for the new `moa` action group if required by TypeScript.                                                                                                            | \~15       |
| `src/components/hermes/__tests__/hermes-mission-control.test.tsx`                 | Update admin hook fixture shape for the new `moa` action group if required by TypeScript.                                                                                                            | \~15       |
| `src/components/hermes/__tests__/hermes-sections.test.tsx`                        | Update admin hook fixture shape for the new `moa` action group if required by TypeScript.                                                                                                            | \~20       |
| `src/components/hermes/chat/__tests__/hermes-chat-tab.test.tsx`                   | Update admin hook fixture shape for the new `moa` action group if required by TypeScript.                                                                                                            | \~15       |
| `src/components/hermes/intelligence/__tests__/intelligence-portal.test.tsx`       | Update admin hook fixture shape for the new `moa` action group if required by TypeScript.                                                                                                            | \~15       |
| `src/components/knowledge-graph/__tests__/knowledge-graph-grounded-chat.test.tsx` | Update admin hook fixture shape for the new `moa` action group if required by TypeScript.                                                                                                            | \~15       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] POST `/__hermes_moa_save` rejects non-loopback, bad Host, bad token, disabled admin mode, wrong method, invalid JSON, invalid payloads, and unknown fields before file writes.
* [ ] Valid payloads accept one aggregator model and one to three reference models with bounded provider, model, temperature, and `max_tokens` values.
* [ ] Missing `config.yaml` returns setup-required state without exposing a raw private path.
* [ ] Existing Hermes config is backed up before mutation and the browser response returns only safe labels.
* [ ] The write updates only `moa.presets[name]` and `moa.default_preset`, while preserving unrelated config keys and unrelated MoA presets.
* [ ] Invalid YAML, non-object config, backup failures, dump failures, and write failures return controlled browser-safe errors without partial success.
* [ ] `useHermesAdmin` exposes a typed MoA save action for later UI work without adding Ministry builder UI.

### Testing Requirements

* [ ] Hermes admin bridge tests cover gates, validation, missing config, invalid config, backup behavior, merge preservation, default preset update, no-write invalid payloads, and no raw path leakage.
* [ ] Parser tests cover valid MoA save responses and malformed payloads.
* [ ] Hook tests cover request serialization, disabled/token/offline states, parser failures, and duplicate in-flight prevention.
* [ ] Focused checks pass: `bunx vitest run scripts/lib/__tests__/hermes-admin-bridge.test.ts src/lib/__tests__/hermes-admin-types.test.ts src/hooks/__tests__/use-hermes-admin.test.tsx`.
* [ ] `bun run typecheck:scripts` and `bun run typecheck` pass.

### Non-Functional Requirements

* [ ] Config writes remain local-only, admin-gated, bounded, and transactional.
* [ ] Browser-visible responses expose no raw home paths, auth JSON paths, account IDs, emails, tokens, command bodies, YAML contents, or secret-shaped strings.
* [ ] Existing chat, command, mission, Pantheon, documents, image, and Obsidian admin actions continue using the same bridge registration and guard behavior.
* [ ] No app database, migration, hosted write path, public demo behavior, dependency, asset, or visible route is introduced.

### Quality Gates

* [ ] All files ASCII-encoded
* [ ] Unix LF line endings
* [ ] Code follows project conventions
* [ ] No user-facing Ministry builder, save UX, or debug surface is added in this endpoint-only session

***

## 8. Implementation Notes

### Working Assumptions

* The endpoint should be named `/__hermes_moa_save`: the Session 06 stub names that path first, Phase 40 keeps Hermes admin writes under `/__hermes_*`, and Session 05 confirmed new admin endpoints are registered through the bridge `ENDPOINTS` list. Planning can proceed because this matches existing route ownership and avoids a separate Vite middleware path.
* The existing `js-yaml` dependency is sufficient for structured Hermes config updates: the Session 06 stub records this assumption, `package.json` already depends on `js-yaml`, and `scripts/lib/hermes-admin-bridge.ts` already imports `load` and `dump`. Planning can proceed without adding a dependency.
* The config path should resolve from `resolveHermesHome(options)` plus `config.yaml`: the PRD names `~/.hermes/config.yaml`, while the current bridge already honors test/config overrides through `resolveHermesHome`. Planning can proceed because this keeps production behavior and temp-fixture tests aligned.

### Conflict Resolutions

* The stub says "POST `/__hermes_moa_save` or the chosen namespaced admin equivalent"; the chosen interpretation is to use `/__hermes_moa_save` because current Hermes admin write endpoints use top-level `/__hermes_*` names and Session 06 has no reason to introduce a new namespace.
* The PRD mentions writing `~/.hermes/config.yaml`, while tests and configured local installs may use `HERMES_HOME`. The chosen interpretation is to write the config under the resolved Hermes home and return only safe labels, never the raw path.

### Key Considerations

* Keep AI OS naming and do not add new global `findtrend` identifiers.
* Preserve the public demo and hosted boundaries; this endpoint must remain a local dev/admin bridge path only.
* Use synthetic fixture values and placeholders shorter than real key patterns in tests and docs.
* Keep the hook and parser surface ready for later Ministry UI without adding a product control in this session.

### Potential Challenges

* YAML merge could accidentally clobber unrelated config: mitigate with tests that include unrelated top-level keys, unrelated `moa` keys, and multiple pre-existing presets.
* Validation could accept a write-shaped payload with hidden fields: mitigate with exact allowed-key checks at every nested payload level and no-write assertions for invalid requests.
* Backup or temp-write failures could leave confusing state: mitigate with backup-before-write, temp-file-and-rename replacement, and controlled failure tests.
* Expanding the hook result shape can break existing typed test fixtures: mitigate by updating known admin mock fixtures and running app typecheck.

### Relevant Considerations

* \[P38] **Upstream ports are semantic, not wholesale**: Translate MoA save behavior into AI OS bridge, parser, and hook owners instead of copying upstream route or middleware files.
* \[P38] **Local control-plane gates are defense in depth**: Preserve socket loopback, Host-header, token/admin, method, body-size, schema, timeout where relevant, and safe-error checks.
* \[P21] **Do not let token-shaped strings or auth headers reach browser state or logs**: MoA save responses and errors must never include config contents, auth paths, provider payloads, or secret-shaped strings.
* \[P00] **Stack conventions**: Bun, Vite 8, TanStack Start, React 19, Radix UI, and Cloudflare Worker compatibility remain baseline constraints.

### Behavioral Quality Focus

Checklist active: Yes

Top behavioral risks for this session:

* Trust boundary bypass: endpoint validation must reject invalid, oversized, or unknown-field payloads before filesystem access.
* Write integrity failure: config mutation must use backup and atomic replacement so a failed save does not silently clobber existing Hermes config.
* Browser leakage: all success and failure responses must remain label-only and sanitized, with raw config paths and YAML contents kept server-side.

***

## 9. Testing Strategy

### Unit Tests

* Test MoA payload readers and endpoint behavior through `scripts/lib/__tests__/hermes-admin-bridge.test.ts` using temp Hermes homes.
* Test response parsing through `src/lib/__tests__/hermes-admin-types.test.ts`.
* Test hook mutation state and request serialization through `src/hooks/__tests__/use-hermes-admin.test.tsx`.

### Integration Tests

* Exercise the admin bridge route map with `/__hermes_moa_save` registered alongside existing Hermes admin endpoints.
* Verify existing command, chat, mission, Pantheon, document, image, and Obsidian admin tests still compile and pass after hook shape changes.

### Runtime Verification

* Use temp config fixtures to save a preset, read the resulting YAML, and verify the intended MoA fields changed while unrelated config survived.
* Confirm missing config and invalid config responses are safe and do not include raw paths.

### Edge Cases

* Empty, whitespace, path-like, oversized, or injection-shaped preset names.
* Missing or malformed aggregator model.
* Zero, four, or malformed reference models.
* Temperature and `max_tokens` outside allowed bounds.
* Unknown root, aggregator, or reference keys.
* Missing `config.yaml`, malformed YAML, YAML array/root scalar, backup copy failure, and temp-write failure.

***

## 10. Dependencies

### Other Sessions

* Depends on: `phase40-session03-shared-redaction-foundation`, `phase40-session04-chat-overrides-and-runtime`, `phase40-session05-command-endpoint`
* Depended by: `phase40-session14-ministry-builder-and-pantheon`, `phase40-session15-ministry-config-analytics-and-save-ux`

***

## Next Steps

Run the `implement` workflow step to begin implementation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/.spec_system/archive/sessions/phase40-session06-moa-save-endpoint/spec.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
