feat(profile): §7 conformance build-out — credbridge, distribution.yaml, cron, manifest

Closes the largest set of PROFILE-DISTRIBUTION-PROTOCOL §7 readiness gaps
surfaced in the 2026-05-23 audit. Profile goes from 4/8 to expected 8/8
once skills/proton-tools/ is committed.

New files:

  credbridge.sh           Personal-assistant variant of the shared-core
                          credbridge pattern. Three credentials in scope:
                          google-workspace (Gmail/Calendar/Contacts),
                          proton-bridge (himalaya IMAP/SMTP), perplexity
                          (raw WebSearch). Plan B marketing platforms
                          explicitly OUT OF SCOPE per CLAUDE.md hard rule.

  validate_access.sh      Emits PASS/BLOCKED/FAIL JSON line per credential.
                          Sourceable from install.sh and standalone. Exit
                          code always 0; status is in the JSON.

  distribution.yaml       Native Hermes install contract (`hermes profile
                          install` reads this). Mirrors cmo/ceo pattern.
                          Documents personal/agnostic naming exception
                          per FRAMEWORK §6.1 — no org suffix because there
                          is exactly one principal.

  cron/steev-daily-briefing.json.template
                          06:30 daily briefing skeleton, ships disabled.
                          Aggregates calendar + flagged emails + due tasks
                          + carried items + brief news scan into a single
                          digest in JP's voice. NEVER auto-sends, NEVER
                          touches business comms (CEO → CMO surface).

manifest.yaml fully rewritten:

  - Added `contract: CONTRACT.md` pointer (was missing)
  - Added inline comment explaining intentional `org:` omission
  - Declared skills/proton-tools (on disk via JP's untracked WIP; declared
    here so manifest matches disk truth once JP commits it)
  - Added `lib:` block (credbridge.sh + validate_access.sh)
  - Added `expected_external_skills:` informational list (google-workspace,
    apple-*, obsidian, himalaya, imessage, perplexity) — these come from
    Hermes' global skills tree per CLAUDE.md "reuse existing core skills"
  - Added `optional_tools:` block (4 MCP servers: proton-calendar/-email/
    -contacts, perplexity)
  - Added `credentials:` block listing the 3 creds + resolution path
  - Promoted `cron:` from empty list to a single steev-daily-briefing
    entry (disabled_on_install: true)
  - Added `sovereignty:` block (qwen3.6-35b-a3b on DGX Spark)

CONTRACT.md frontmatter migrated from legacy `tier: S` to T1 per
FRONTMATTER-SPEC. Added required fields (name, last_reviewed,
description, depends_on).

skills/proton-tools/ left untracked — that's JP's WIP, not mine to
commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Svrnty 2026-05-23 19:01:55 -04:00
parent 66c742c219
commit 2db2d26250
6 changed files with 278 additions and 14 deletions

View File

@ -1,10 +1,15 @@
--- ---
tier: S name: steev-contract
tier: T1
status: active status: active
owner: jp owner: jp
source: hand source: hand
last_reviewed: 2026-05-23
review_by: 2026-08-21 review_by: 2026-08-21
note: Steev profile contract — this file wins for the Steev profile description: steev profile behavior contract — what Steev does, doesn't do, edge cases. Tier T1 — this file wins for the steev profile.
depends_on:
- profile-distribution-protocol
note: legacy tier S remapped to T1 per FRONTMATTER-SPEC 2026-05-23. Required fields filled (name, last_reviewed, description) per §7 audit.
--- ---
# Steev — Source of Truth # Steev — Source of Truth

94
credbridge.sh Executable file
View File

@ -0,0 +1,94 @@
#!/usr/bin/env bash
# credbridge.sh — resolve credctl credentials into env vars for steev's
# personal-flow tools, then exec the CLI. Secrets NEVER echoed, logged, or
# written to disk.
#
# Usage: credbridge.sh <tool> [args...]
# tools: google-workspace | proton-bridge | perplexity
#
# Per PROFILE-DISTRIBUTION-PROTOCOL §3 (shared core, "credbridge" row) and §6
# (Conventions → Secrets), every profile distribution exposes credentials via
# this verb chain: credctl set → credenv → exec, with secrets per-call only.
#
# This is the personal-assistant variant of the credbridge pattern. Steev's
# cred surface is narrow by design:
#
# - google-workspace: Gmail + Calendar + Contacts (OAuth blob from credctl)
# - proton-bridge: IMAP/SMTP password for the local Proton Bridge T6
# sidecar — gives Steev access to JP's Proton mail via
# himalaya (cleartext on 127.0.0.1 only)
# - perplexity: Perplexity API key for WebSearch toolset (lightweight
# — most Steev work uses the perplexity MCP instead)
#
# Plan B marketing platforms (WooCommerce, Mailchimp, Meta, GA4, etc.) are OUT
# OF SCOPE here — that's cmo-planb's credbridge. Steev MUST NEVER resolve a
# marketing platform credential. The CLAUDE.md "no access to Plan B marketing
# platform credentials" rule is enforced by omission from this case statement.
#
# Design notes (same as cmo/credbridge.sh — shared core):
# - credctl values read into local vars, exported straight to the child env
# - JSON-valued creds (google-workspace OAuth) parsed via `node -e` reading
# from stdin so the value never lands on argv / process list
# - No `echo $secret`. set +x stays off.
set -euo pipefail
# Paths env-overridable for portability; defaults match the JP install.
CREDCTL="${CREDCTL:-/home/svrnty/workspaces/cortex/L6-svrnty.core-credentials/credctl}"
STEEV_LIB="${STEEV_LIB:-/home/svrnty/.hermes/steev}"
die() { printf '{"error":"%s"}\n' "$1" >&2; exit 1; }
[ $# -ge 1 ] || die "usage: credbridge.sh <google-workspace|proton-bridge|perplexity> [args...]"
TOOL="$1"; shift
[ -x "$CREDCTL" ] || die "credctl not found/executable at $CREDCTL"
# cred_raw <name> — print unmasked credential value to stdout. Caller captures
# into a var; value never displayed. Strips the "Value:" header from credctl.
cred_raw() {
"$CREDCTL" get "$1" --unmask 2>/dev/null \
| sed -n '/^Value:/,$p' | sed '1s/^Value:[[:space:]]*//'
}
# json_field <json> <key> — extract a string field via node; value never on argv.
json_field() {
printf '%s' "$1" | node -e '
let s="";process.stdin.on("data",d=>s+=d);
process.stdin.on("end",()=>{try{const o=JSON.parse(s);
const v=o[process.argv[1]];process.stdout.write(v==null?"":String(v));
}catch(e){process.stdout.write("");}});' "$2"
}
case "$TOOL" in
google-workspace)
# Gmail Data API + Calendar API + People API all expect a bearer token
# minted from this service-account / OAuth blob. The blob is JSON; we
# export the whole document so the child CLI can introspect scope.
GW_JSON="$(cred_raw google-workspace)"
[ -n "$GW_JSON" ] || die "credctl: google-workspace not set"
export GOOGLE_WORKSPACE_CREDENTIALS_JSON="$GW_JSON"
exec "$@"
;;
proton-bridge)
# Steev reads JP's Proton inbox via the local Proton Bridge IMAP daemon
# (T6 sidecar — see PROFILE-DISTRIBUTION-PROTOCOL §4.T6). credctl stores
# the bridge password (rotates when JP rotates the bridge).
PB_PASS="$(cred_raw proton-bridge-imap)"
[ -n "$PB_PASS" ] || die "credctl: proton-bridge-imap not set"
export PROTON_BRIDGE_IMAP_PASSWORD="$PB_PASS"
exec "$@"
;;
perplexity)
# Lightweight WebSearch path. Most Steev research goes through the
# perplexity MCP server (which holds its own key); this credbridge entry
# exists for scripts that need a raw key (rare).
PPL_KEY="$(cred_raw perplexity-api)"
[ -n "$PPL_KEY" ] || die "credctl: perplexity-api not set"
export PERPLEXITY_API_KEY="$PPL_KEY"
exec "$@"
;;
*)
die "unknown tool: $TOOL (allowed: google-workspace|proton-bridge|perplexity)"
;;
esac

View File

@ -0,0 +1,40 @@
{
"id": "steev-daily-briefing",
"name": "steev-daily-briefing",
"prompt": "Steev daily briefing. DB=${HERMES_HOME}/steev/steev.db, helper=${HERMES_HOME}/steev/steev_db.py.\n1. runtime-get: if agent_runtime.status='halted' → STOP, output \"halted, skipping\", do nothing else.\n2. Aggregate today's context:\n - calendar events from google-workspace (today + tomorrow morning)\n - flagged + unread emails from proton-bridge (himalaya) + google-workspace (gmail)\n - due tasks from apple-reminders + obsidian vault (~/vaults/steev/Tasks/)\n - carried items from steev.db (briefings.carried_over)\n - brief news scan via perplexity (1-2 items only)\n3. Compose a single digest in JP's voice (FR/EN per JP's language preference for that day). Surface only what needs JP's attention.\n4. Persist digest to steev.db (briefings table) as status='draft'.\n5. Output a 5W summary of items surfaced.\n6. NEVER auto-send. NEVER touch business comms surface (that's CEO → CMO).",
"skills": [
"steev-agent"
],
"skill": "steev-agent",
"model": null,
"provider": null,
"base_url": null,
"script": null,
"no_agent": false,
"context_from": null,
"schedule": {
"kind": "cron",
"expr": "30 6 * * *",
"display": "06:30 daily"
},
"schedule_display": "06:30 daily",
"repeat": {
"times": null,
"completed": 0
},
"enabled": false,
"state": "paused",
"paused_at": null,
"paused_reason": "installed paused — enable via: hermes cron resume steev-daily-briefing",
"created_at": null,
"next_run_at": null,
"last_run_at": null,
"last_status": null,
"last_error": null,
"last_delivery_error": null,
"deliver": "local",
"origin": null,
"enabled_toolsets": null,
"workdir": "${HERMES_HOME}/steev",
"profile": "steev"
}

29
distribution.yaml Normal file
View File

@ -0,0 +1,29 @@
# Hermes profile distribution manifest — native Hermes install contract.
# Used by `hermes profile install`. Distinct from manifest.yaml (our workspace
# convention layered on top — see ../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md).
name: steev
version: 1.0.0
description: "Steev — JP's personal AI chief of staff. Daily briefing (calendar + flagged emails + due tasks + carried items + brief news scan), inbox triage, comms drafting in JP's voice (French/English bilingual), and business-task delegation to ceo-planb. Personal-flow manager — no Plan B marketing surface. Sovereign on qwen3.6-35b-a3b."
hermes_requires: ">=0.14.0"
author: "Svrnty / JP <mathias@openharbor.io>"
license: "proprietary"
# Steev is personal/agnostic per CORTEX-OS-FRAMEWORK §6.1 — no org suffix.
# Profile name = `steev` (not `steev-<org>`) because there is exactly one
# principal: JP. Cloning steev for another principal = rename in
# distribution.yaml only; no other code changes.
env_requires: [] # credentials provisioned via credctl at install/runtime, never in env
distribution_owned:
- AGENT.md
- CONTRACT.md
- CLAUDE.md
- README.md
- manifest.yaml
- schema.sql
- install.sh
- credbridge.sh
- validate_access.sh
- skills/
- cron/

View File

@ -1,19 +1,73 @@
# Steev profile distribution manifest — machine-readable identity + install contract. # Steev profile distribution manifest — machine-readable identity + install contract.
# Read by install.sh. Convention shared by all profile distributions (see PROFILE-DISTRIBUTION-SPEC.md). # Read by install.sh. Convention shared by all Hermes profile distributions
profile: steev # (see ../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md — the canonical protocol).
kind: profile-distribution profile: steev # Hermes profile name (personal — no org suffix per FRAMEWORK §6.1)
role: steev kind: profile-distribution # family marker; steev = personal-assistant reference impl
role: personal-assistant # function — Chief of Staff for one principal (JP)
# org: ~ # intentionally omitted — steev is personal/agnostic
version: 1.0.0 version: 1.0.0
identity: AGENT.md identity: AGENT.md # WHO (role, mission, boundaries)
reference: docs/STEEV-MASTER.md contract: CONTRACT.md # behavior contract — tier T1 (this file wins)
reference: docs/STEEV-MASTER.md # full operating source of truth
skills: skills: # exposed to Hermes via skills.external_dirs (→ <repo>/skills)
- skills/steev-agent # personal assistant orchestrator - skills/steev-agent # orchestrator — daily briefing, inbox triage, comms drafting,
# business delegation to ceo-planb
- skills/proton-tools # Proton Calendar + Email + Contacts (24-tool reference) —
# uses the 3 cortex MCP servers (proton-calendar/-email/-contacts)
# Role tools = scripts at repo root (the "lib"), reached through credbridge.
# Personal-flow surface only; Plan B marketing CLIs out of scope (cmo-planb owns those).
lib:
- credbridge.sh # credctl → env → google-workspace / proton-bridge / perplexity
- validate_access.sh # PASS / BLOCKED / FAIL per credential per §7
# Hermes built-in / external skills Steev reuses but does NOT vendor (per CLAUDE.md
# "reuse existing core skills"). Informational — these come from Hermes' global skills
# tree (~/.hermes/skills/) or external skill libraries the principal already installed.
expected_external_skills:
- google-workspace # Gmail + Calendar + Contacts
- apple-notes # macOS-local via osascript
- apple-reminders # macOS-local via osascript
- obsidian # ~/vaults/steev PKM
- himalaya # IMAP/SMTP via proton-bridge sidecar
- imessage # macOS-local
- perplexity # WebSearch toolset (lightweight; MCP preferred)
# MCP servers Steev consumes. Names match runtime-prefixed form (mcp_<server>_<tool>).
optional_tools:
- mcp_proton_calendar # 8-tool Proton Calendar facade
- mcp_proton_email # 10-tool Proton Email facade
- mcp_proton_contacts # 6-tool Proton Contacts facade
- mcp_perplexity # research / WebSearch (key held by MCP server, not credbridge)
requires_tools: [terminal, memory_tool] requires_tools: [terminal, memory_tool]
credentials: # validated by validate_access.sh
- name: google-workspace
purpose: Gmail + Calendar + Contacts read/write for daily briefing + inbox triage
resolved_via: credbridge.sh
- name: proton-bridge-imap
purpose: local Proton Bridge IMAP/SMTP password (himalaya path)
resolved_via: credbridge.sh
- name: perplexity-api
purpose: Perplexity API key for raw WebSearch (MCP path preferred)
resolved_via: credbridge.sh
db: db:
file: steev.db # runtime state; created from schema.sql; never committed file: steev.db # runtime state; created from schema.sql; never committed
schema: schema.sql schema: schema.sql # briefings + inbox_items + invocations + agent_runtime
cron: [] # daily-briefing cron registered disabled at launch cron:
- id: steev-daily-briefing
schedule: "30 6 * * *" # 06:30 local — well before JP's start of day
skill: steev-agent
input: { mode: daily-briefing }
disabled_on_install: true # ships disabled per profile protocol §6 (Safety)
template: cron/steev-daily-briefing.json.template
sovereignty:
llm_model: qwen-local/qwen3.6-35b-a3b
host: dgx-spark
external_api_dependencies:
- perplexity # WebSearch only; build-time research path. Daily briefing scan uses 1-2 items.

42
validate_access.sh Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env bash
# validate_access.sh — report PASS / BLOCKED / FAIL per credential, per
# PROFILE-DISTRIBUTION-PROTOCOL §7 (readiness checklist, "credbridge resolves
# every credential the manifest lists; validate_access reports PASS/BLOCKED/
# FAIL"). Sourceable from install.sh and standalone.
#
# Usage: validate_access.sh
# Exit code: always 0. Emits one JSON line per credential, suitable for jq /
# log aggregation.
#
# Statuses:
# PASS credctl key set + non-empty
# BLOCKED key absent or empty — actionable: run `credctl set <name>`
# FAIL credctl itself missing or broken — environmental issue
set -uo pipefail
CREDCTL="${CREDCTL:-/home/svrnty/workspaces/cortex/L6-svrnty.core-credentials/credctl}"
CREDENTIALS=(
google-workspace
proton-bridge-imap
perplexity-api
)
check() {
local name="$1" status reason
if [ ! -x "$CREDCTL" ]; then
status="FAIL"; reason="credctl not found at $CREDCTL"
elif ! "$CREDCTL" list 2>/dev/null | grep -q "^${name}[[:space:]]"; then
status="BLOCKED"; reason="credctl key not set — run: credctl set ${name}"
elif [ -z "$("$CREDCTL" get "$name" --unmask 2>/dev/null | sed -n '/^Value:/,$p' | sed '1s/^Value:[[:space:]]*//')" ]; then
status="BLOCKED"; reason="key exists but value empty"
else
status="PASS"; reason="present"
fi
printf '{"credential":"%s","status":"%s","reason":"%s"}\n' "$name" "$status" "$reason"
}
for cred in "${CREDENTIALS[@]}"; do
check "$cred"
done