Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ Primary REST: `POST /v1/proof` → `ProofReceipt` with claim `controlled_proof_n
### Hermes (agentic operator)

1. Install package (`pip install -e '.[dev]'`).
2. Copy skill: `cp -R skills/hermes-continuity-forge ~/.hermes/skills/` (or your Hermes skills path).
2. Copy skill: `cp -R skills/hermes-continuity-forge "${HERMES_HOME:-$HOME/.hermes}/skills"/` (or your Hermes skills path).
3. Wire MCP stdio to `.venv/bin/continuity-forge-mcp` — see [`docs/hermes/mcp.example.json`](docs/hermes/mcp.example.json).
4. Read [`docs/hermes/README.md`](docs/hermes/README.md).

Expand Down Expand Up @@ -277,8 +277,8 @@ See `skills/scriptwriting/SKILL.md` and `skills/scriptwriting/references/continu

Install both:
```bash
cp -R skills/scriptwriting ~/.hermes/skills/
cp -R skills/hermes-continuity-forge ~/.hermes/skills/
cp -R skills/scriptwriting "${HERMES_HOME:-$HOME/.hermes}/skills"/
cp -R skills/hermes-continuity-forge "${HERMES_HOME:-$HOME/.hermes}/skills"/
```

## Symbolic Cinematic Layer: kubrick Skill
Expand Down Expand Up @@ -309,6 +309,6 @@ See:

Install:
```bash
cp -R skills/kubrick ~/.hermes/skills/
cp -R skills/hermes-continuity-forge ~/.hermes/skills/
bash skills/kubrick/install.sh --dry-run # review, then --apply
cp -R skills/hermes-continuity-forge "${HERMES_HOME:-$HOME/.hermes}/skills"/
```
108 changes: 64 additions & 44 deletions apps/mcp/src/continuity_forge_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,36 +518,46 @@ def queue_generation(
idempotency_key: str = "mcp-queue-generation",
rationale: str = "PROPOSED generation (no canon write)",
seed: str = "0",
expected_state_hash: str | None = None,
) -> dict[str, Any]:
"""Generate a PROPOSED mock media candidate for a shot (no canon mutation).

MutationEnvelope fields are validated for audit consistency; output remains
PROPOSED and never becomes film canon.
PROPOSED and never becomes film canon. Pass the reviewed project state_hash;
omission binds to a fresh server snapshot. The store lock covers generation
and persistence within this runtime (not across independent processes).
"""
MutationEnvelope.from_parts(
runtime = _rt()
project = runtime.project_store.get_project(document_key)
if project is None or not project.shot_contracts:
raise ValueError("project or shot contracts not found")
envelope = MutationEnvelope.from_parts(
actor_id=actor_id,
authorization_scope=authorization_scope,
idempotency_key=idempotency_key,
rationale=rationale,
)
project = _rt().project_store.get_project(document_key)
if project is None or not project.shot_contracts:
raise ValueError("project or shot contracts not found")
contract = next(
(
c
for c in project.shot_contracts.get("contracts") or []
if str(c.get("shot_id")) == shot_id
expected_state_hash=(
expected_state_hash if expected_state_hash is not None else project.state_hash
),
None,
)
if contract is None:
raise ValueError("shot not found")
candidate = _rt().gateway.generate_for_shot(contract, seed=seed)
artifact_store = _rt().artifact_store
if artifact_store is not None:
artifact_store.put(candidate)
return candidate.model_dump(mode="json")
with runtime.project_store.candidate_write(document_key, envelope):
contract = next(
(
c
for c in project.shot_contracts.get("contracts") or []
if str(c.get("shot_id")) == shot_id
),
None,
)
if contract is None:
raise ValueError("shot not found")
candidate = runtime.gateway.generate_for_shot(contract, seed=seed)
artifact_store = runtime.artifact_store
if artifact_store is not None:
# Recheck before persistence, including re-entrant provider callbacks.
with runtime.project_store.candidate_write(document_key, envelope):
artifact_store.put(candidate)
return candidate.model_dump(mode="json")


@mcp.tool()
Expand All @@ -561,42 +571,52 @@ def run_shot_repair_loop(
seed: str = "0",
max_attempts: int = 3,
fail_first: bool = False,
expected_state_hash: str | None = None,
) -> dict[str, Any]:
"""Run generate→validate→repair loop for one shot (mock worker).

MutationEnvelope fields are validated for audit consistency; accepted
candidates remain PROPOSED.
candidates remain PROPOSED. Pass the reviewed project state_hash; omission
binds to a fresh server snapshot. The store lock covers the loop and
persistence within this runtime (not across independent processes).
"""
MutationEnvelope.from_parts(
runtime = _rt()
project = runtime.project_store.get_project(document_key)
if project is None or not project.shot_contracts:
raise ValueError("project or shot contracts not found")
envelope = MutationEnvelope.from_parts(
actor_id=actor_id,
authorization_scope=authorization_scope,
idempotency_key=idempotency_key,
rationale=rationale,
)
project = _rt().project_store.get_project(document_key)
if project is None or not project.shot_contracts:
raise ValueError("project or shot contracts not found")
contract = next(
(
c
for c in project.shot_contracts.get("contracts") or []
if str(c.get("shot_id")) == shot_id
expected_state_hash=(
expected_state_hash if expected_state_hash is not None else project.state_hash
),
None,
)
if contract is None:
raise ValueError("shot not found")
result = run_repair_loop(
contract,
gateway=_rt().gateway,
seed=seed,
max_attempts=max_attempts,
fail_first=fail_first,
)
artifact_store = _rt().artifact_store
if result.accepted_candidate is not None and artifact_store is not None:
artifact_store.put(result.accepted_candidate)
return result.model_dump(mode="json")
with runtime.project_store.candidate_write(document_key, envelope):
contract = next(
(
c
for c in project.shot_contracts.get("contracts") or []
if str(c.get("shot_id")) == shot_id
),
None,
)
if contract is None:
raise ValueError("shot not found")
result = run_repair_loop(
contract,
gateway=runtime.gateway,
seed=seed,
max_attempts=max_attempts,
fail_first=fail_first,
)
artifact_store = runtime.artifact_store
if result.accepted_candidate is not None and artifact_store is not None:
# Recheck before persistence, including re-entrant provider callbacks.
with runtime.project_store.candidate_write(document_key, envelope):
artifact_store.put(result.accepted_candidate)
return result.model_dump(mode="json")


def main() -> None:
Expand Down
18 changes: 9 additions & 9 deletions docs/hermes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Copy (or symlink) the skill into Hermes’ skills directory:

```bash
# from continuity-forge repo root
mkdir -p ~/.hermes/skills # adjust if your Hermes install uses another path
cp -R skills/hermes-continuity-forge ~/.hermes/skills/
mkdir -p "${HERMES_HOME:-$HOME/.hermes}/skills" # adjust if your Hermes install uses another path
cp -R skills/hermes-continuity-forge "${HERMES_HOME:-$HOME/.hermes}/skills"/
# or project-local, if Hermes supports workspace skills:
# cp -R skills/hermes-continuity-forge /path/to/workspace/.hermes/skills/
```
Expand Down Expand Up @@ -47,17 +47,17 @@ In addition to the operator skill (`hermes-continuity-forge`), the repo ships `s
**Kubrick works completely on its own inside Hermes** (no continuity-forge required). The skill is distributed by simple directory copy:

```bash
pip install continuity-forge[kubrick-helpers]
python -m pip install -e '.[kubrick-helpers]' # Python 3.12+, repo root
```

This provides `kubrick_helpers` Python package + `kubrick-retrieve` / `kubrick-evolve` CLIs.

Install it the same way:

```bash
cp -R skills/kubrick ~/.hermes/skills/
bash skills/kubrick/install.sh --dry-run # review, then --apply
# or
cp -R skills/kubrick ~/.hermes/skills/creative/
bash skills/kubrick/install.sh creative --dry-run # review, then --apply
```

See `skills/kubrick/README.md` and `skills/kubrick/SKILL.md` for details on its executable retrieval helper and self-evolution system.
Expand Down Expand Up @@ -168,8 +168,8 @@ See `skills/kubrick/references/continuity-forge-integration.md` for exact handof

Install:
```bash
cp -R skills/kubrick ~/.hermes/skills/
cp -R skills/hermes-continuity-forge ~/.hermes/skills/
bash skills/kubrick/install.sh --dry-run # review, then --apply
cp -R skills/hermes-continuity-forge "${HERMES_HOME:-$HOME/.hermes}/skills"/
```

## Symbolic Cinematic Layer: kubrick Skill
Expand Down Expand Up @@ -207,5 +207,5 @@ See skills/kubrick/references/continuity-forge-integration.md for exact handoff
Both skills are designed to be used together. The kubrick skill produces high-quality, drift-resistant creative material with sophisticated symbolic layer. The operator skill ensures it is governed by the deterministic kernel.

Install:
cp -R skills/kubrick ~/.hermes/skills/
cp -R skills/hermes-continuity-forge ~/.hermes/skills/
bash skills/kubrick/install.sh --dry-run # review, then --apply
cp -R skills/hermes-continuity-forge "${HERMES_HOME:-$HOME/.hermes}/skills"/
Loading
Loading