feat(steev): Wave 8 PAUSE-walk — apply Q4-Q10 + bte leak fix + proton-tools SKILL.md

Q4: confirm personal-scope discriminators (chat_facing, delegates_to=[ceo-planb], sovereign_only=false)
Q5: drop google-workspace cred — builtin manages own OAuth via Hermes hub (not credctl vault)
Q6: split proton-bridge-imap → proton-bridge-imap-user + proton-bridge-imap-pass (vault exact-match)
Q7: rename perplexity-api → perplexity (vault exact-match)
Q8: add 3 proton vault entries (account-email, account-password, mailbox-password)
Q9: install.sh F6 — MCP allowlist materialization; wires 3 proton MCPs, removes bte (hard-rule leak)
Q10: macOS-only externals annotated os_constraint:darwin; install.sh F7 emits INFO on non-Darwin

credbridge.sh: drop google-workspace case, rewrite proton-bridge to use 2 vault entries, rename perplexity case
Disclosure §7 rewritten with 6 credentials matching vault exact-name policy (DISCLOSURE-SCHEMA §4.5)
Disclosure §12 PAUSE table marked all 8 rows RESOLVED (rows 1-7 Wave 8, row 8 Wave 7)

Untracked skills/proton-tools/SKILL.md (90 lines, declared in manifest since Wave 4) — committed for clone-ability

Verified:
  hermes -p steev skills list → 6 enabled (matches disclosure.skills declaration)
  hermes -p steev mcp list → 3 entries (proton-calendar, proton-email, proton-contacts); bte removed
  F7 on Linux host correctly suppresses macOS-only externals

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Svrnty 2026-05-24 18:13:40 -04:00
parent 959b8c8871
commit 2491d48151
5 changed files with 253 additions and 67 deletions

View File

@ -76,17 +76,20 @@ No direct HTTP/gRPC sovereign API calls. Indirect access flows through the (curr
No `cortex/L6-*` or `cortex/PG-*` libraries consumed at runtime. `lib/` scripts (`credbridge.sh`, `validate_access.sh`) are repo-local utility shims, not cortex tools. No `cortex/L6-*` or `cortex/PG-*` libraries consumed at runtime. `lib/` scripts (`credbridge.sh`, `validate_access.sh`) are repo-local utility shims, not cortex tools.
## §7 Credentials (3 declared) ## §7 Credentials (6 declared)
Per `disclosure.credentials` allowlist. Names + scopes only — NEVER values. Pre-push check 6.d enforces vault_name exact-match. Per `disclosure.credentials` allowlist. Names + scopes only — NEVER values. Pre-push check 6.d enforces vault_name exact-match. **Wave 8 (2026-05-24): aligned with vault.**
| Vault name | Status | Scope | Used by | Governance | | Vault name | Status | Scope | Used by | Governance |
|---|---|---|---|---| |---|---|---|---|---|
| `google-workspace` | required | read-write | `credbridge.sh` | JP-personal; Gmail+Calendar+Contacts for briefing + inbox triage | | `proton-bridge-imap-user` | required | read | `credbridge.sh` | JP-personal; local Proton Bridge IMAP/SMTP username (himalaya path) |
| `proton-bridge-imap` | required | read-write | `credbridge.sh` | JP-personal; local Proton Bridge IMAP/SMTP (himalaya path) | | `proton-bridge-imap-pass` | required | read | `credbridge.sh` | JP-personal; local Proton Bridge IMAP/SMTP password (himalaya path) |
| `perplexity-api` | optional | read | `credbridge.sh` | JP-personal; WebSearch fallback (MCP path preferred) | | `perplexity` | optional | read | `credbridge.sh` | JP-personal; WebSearch fallback (MCP path preferred) |
| `proton-account-email` | required | read | `credbridge.sh`, `mcp_proton_email` | JP-personal; Proton account email (consumed by proton-email MCP server) |
| `proton-account-password` | required | read | `credbridge.sh`, `mcp_proton_email` | JP-personal; Proton account password (consumed by proton-email MCP server) |
| `proton-mailbox-password` | required | read | `credbridge.sh`, `mcp_proton_email` | JP-personal; Proton mailbox E2E key for mail decryption |
> **PENDING JP REVIEW** — Per Wave-3 recommendations §5a, all three declared names are reported by audit as not exact-matching the vault (`credctl list` shows `proton-bridge-imap-pass`/`-user` split, `perplexity` without `-api`, and `google-workspace` plausibly absent or composite). Cred-rename rows are governance-class W3.4 and require JP decision (manifest-rename vs vault-rename vs bundle-indirection) — surfaced in §12. > **google-workspace removed Wave 8** — Hermes builtin `google-workspace` skill manages its own OAuth flow via Hermes hub, not credctl vault. credbridge.sh google-workspace case dropped accordingly.
## §8 Cron (1) ## §8 Cron (1)
@ -118,20 +121,25 @@ Per `disclosure.credentials` allowlist. Names + scopes only — NEVER values. Pr
- Standards: `../sot/04-STANDARDS/FRONTMATTER-SPEC.md`, `../sot/04-STANDARDS/SOT-ENFORCEMENT.md`, `../sot/04-STANDARDS/DISCLOSURE-SCHEMA.md` - Standards: `../sot/04-STANDARDS/FRONTMATTER-SPEC.md`, `../sot/04-STANDARDS/SOT-ENFORCEMENT.md`, `../sot/04-STANDARDS/DISCLOSURE-SCHEMA.md`
- Brand master ref: omitted (scope: personal) — steev serves JP personally, not a brand/org - Brand master ref: omitted (scope: personal) — steev serves JP personally, not a brand/org
## §12 Open issues + next steps (PENDING JP REVIEW) ## §12 Open issues + next steps
Rows below are **PAUSED for JP** per W3.4 governance-class rule. Wave-4 applies auto-approved rows only (REMOVE bte MCP + DROP 17 builtins + scaffold disclosure block). JP must mark each PAUSE row approve/reject/edit before next apply wave. All 8 Wave-3 PAUSE rows resolved in **Wave 8 (2026-05-24)**. Audit trail retained below.
| # | Topic | Recommended action | Why PAUSED | | # | Topic | Resolution | Wave |
|---|---|---|---| |---|---|---|---|
| 1 | Personal-scope discriminator values (`chat_facing: true`, `delegates_to: [ceo-planb]`, `sovereign_only: false`) | Confirm values | New disclosure surface; JP confirms intent matches CLAUDE.md L7-L8 + CONTRACT delegation chain | | 1 | Personal-scope discriminator values (`chat_facing: true`, `delegates_to: [ceo-planb]`, `sovereign_only: false`) | **CONFIRMED** (Q4). Matches CLAUDE.md L7-L8 + CONTRACT delegation chain. | 8 |
| 2 | Cred `google-workspace` not in vault | (a) add composite OAuth JSON to vault, OR (b) split manifest into per-cred entries matching vault | Cred binding (W3.4) | | 2 | Cred `google-workspace` not in vault | **REMOVED** (Q5 + scope-expansion). Builtin manages own OAuth via Hermes hub; no credctl vault entry needed. credbridge.sh google-workspace case dropped. | 8 |
| 3 | Cred `proton-bridge-imap` vs vault `proton-bridge-imap-pass` + `proton-bridge-imap-user` | Rename manifest entry to TWO entries matching vault | Cred binding (W3.4) | | 3 | Cred `proton-bridge-imap` vs vault `proton-bridge-imap-pass` + `proton-bridge-imap-user` | **SPLIT** (Q6). Manifest split into 2 entries matching vault. credbridge.sh exports both `PROTON_BRIDGE_IMAP_USER` + `PROTON_BRIDGE_IMAP_PASSWORD`. | 8 |
| 4 | Cred `perplexity-api` vs vault `perplexity` | Rename manifest declaration `perplexity-api``perplexity` (exact-match per schema §4.5) | Cred binding (W3.4) | | 4 | Cred `perplexity-api` vs vault `perplexity` | **RENAMED** (Q7). Manifest + credbridge.sh updated to `perplexity` (exact-match per schema §4.5). | 8 |
| 5 | 5 vault entries plausibly steev-scope but undeclared (`proton-account-email`, `proton-account-password`, `proton-mailbox-password`, `proton-bridge-imap-pass`, `proton-bridge-imap-user`) | ADD to `disclosure.credentials` after MCP install confirms which are consumed | Cred binding (W3.4); also depends on MCP install (row 6) | | 5 | 3 proton vault entries undeclared (`proton-account-email`, `proton-account-password`, `proton-mailbox-password`) | **ADDED** (Q8). Declared in `disclosure.credentials` w/ `used_by: [credbridge.sh, mcp_proton_email]`. The other 2 (`proton-bridge-imap-pass/-user`) covered by row 3. | 8 |
| 6 | 4 declared MCP servers absent from `hermes mcp list` (`mcp_proton_calendar`, `mcp_proton_email`, `mcp_proton_contacts`, `mcp_perplexity`) | Confirm install order — Wave-4 install.sh patch, or deferred | Install gap; cred-adjacent | | 6 | 4 declared MCP servers absent from `hermes mcp list` (`mcp_proton_calendar`, `mcp_proton_email`, `mcp_proton_contacts`, `mcp_perplexity`) | **MATERIALIZED 3/4** (Q9). install.sh F6 wires 3 proton MCPs into per-profile config from `optional_tools`. Also removed bte (hard-rule leak discovered Wave 8). mcp_perplexity DEFERRED (server not in global `hermes mcp list`). | 8 |
| 7 | macOS-only externals (`apple-notes`, `apple-reminders`, `imessage`) in `expected_external_skills` | Gate on OS in `install.sh`, or document as macOS-host-only | OS-platform decision | | 7 | macOS-only externals (`apple-notes`, `apple-reminders`, `imessage`) in `expected_external_skills` | **OS-GATED** (Q10). Annotated `os_constraint: darwin`. install.sh F7 emits INFO on non-Darwin hosts that these are unavailable. | 8 |
| 8 | Pre-push hook check 6 not yet wired (curator/lib/pre-push.sh patch belongs to Wave-5+) | Wire check 6 per DISCLOSURE-SCHEMA §6 | Cross-profile rollup (Wave-5) | | 8 | Pre-push hook check 6 not yet wired (curator/lib/pre-push.sh patch belongs to Wave-5+) | **WIRED** (Wave 7 D6). Subrepo pre-push hook installed via `install.sh F4`; main repo hook covers 6.a-6.f. | 7 |
### Wave 8 follow-ups (not PAUSE — separate work)
- **mcp_perplexity install** — server doesn't exist in global `hermes mcp list`. When provisioned, install.sh F6 will materialize automatically (no code change).
- **Per-tool enumeration in `disclosure.mcp_servers`** — currently `[]` w/ install.sh F6 driven from `optional_tools`. Wave 8.5: introspect each MCP server, populate `disclosure.mcp_servers[*].tools[]` per DISCLOSURE-SCHEMA §4.2.
## §13 Related ## §13 Related

View File

@ -4,7 +4,7 @@
# written to disk. # written to disk.
# #
# Usage: credbridge.sh <tool> [args...] # Usage: credbridge.sh <tool> [args...]
# tools: google-workspace | proton-bridge | perplexity # tools: proton-bridge | perplexity
# #
# Per PROFILE-DISTRIBUTION-PROTOCOL §3 (shared core, "credbridge" row) and §6 # Per PROFILE-DISTRIBUTION-PROTOCOL §3 (shared core, "credbridge" row) and §6
# (Conventions → Secrets), every profile distribution exposes credentials via # (Conventions → Secrets), every profile distribution exposes credentials via
@ -13,13 +13,16 @@
# This is the personal-assistant variant of the credbridge pattern. Steev's # This is the personal-assistant variant of the credbridge pattern. Steev's
# cred surface is narrow by design: # cred surface is narrow by design:
# #
# - google-workspace: Gmail + Calendar + Contacts (OAuth blob from credctl) # - proton-bridge: IMAP/SMTP user + password for the local Proton Bridge
# - proton-bridge: IMAP/SMTP password for the local Proton Bridge T6 # T6 sidecar — gives Steev access to JP's Proton mail
# sidecar — gives Steev access to JP's Proton mail via # via himalaya (cleartext on 127.0.0.1 only)
# himalaya (cleartext on 127.0.0.1 only)
# - perplexity: Perplexity API key for WebSearch toolset (lightweight # - perplexity: Perplexity API key for WebSearch toolset (lightweight
# — most Steev work uses the perplexity MCP instead) # — most Steev work uses the perplexity MCP instead)
# #
# Wave 8 (2026-05-24): google-workspace case REMOVED — Hermes builtin
# google-workspace skill manages its own OAuth flow via the Hermes hub, not
# the credctl vault. Vault contains no google-workspace-* entries.
#
# Plan B marketing platforms (WooCommerce, Mailchimp, Meta, GA4, etc.) are OUT # 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 # 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 # marketing platform credential. The CLAUDE.md "no access to Plan B marketing
@ -27,8 +30,6 @@
# #
# Design notes (same as cmo/credbridge.sh — shared core): # Design notes (same as cmo/credbridge.sh — shared core):
# - credctl values read into local vars, exported straight to the child env # - 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. # - No `echo $secret`. set +x stays off.
set -euo pipefail set -euo pipefail
@ -39,7 +40,7 @@ STEEV_LIB="${STEEV_LIB:-/home/svrnty/.hermes/steev}"
die() { printf '{"error":"%s"}\n' "$1" >&2; exit 1; } die() { printf '{"error":"%s"}\n' "$1" >&2; exit 1; }
[ $# -ge 1 ] || die "usage: credbridge.sh <google-workspace|proton-bridge|perplexity> [args...]" [ $# -ge 1 ] || die "usage: credbridge.sh <proton-bridge|perplexity> [args...]"
TOOL="$1"; shift TOOL="$1"; shift
[ -x "$CREDCTL" ] || die "credctl not found/executable at $CREDCTL" [ -x "$CREDCTL" ] || die "credctl not found/executable at $CREDCTL"
@ -51,44 +52,30 @@ cred_raw() {
| sed -n '/^Value:/,$p' | sed '1s/^Value:[[:space:]]*//' | 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 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) proton-bridge)
# Steev reads JP's Proton inbox via the local Proton Bridge IMAP daemon # Steev reads JP's Proton inbox via the local Proton Bridge IMAP daemon
# (T6 sidecar — see PROFILE-DISTRIBUTION-PROTOCOL §4.T6). credctl stores # (T6 sidecar — see PROFILE-DISTRIBUTION-PROTOCOL §4.T6). credctl stores
# the bridge password (rotates when JP rotates the bridge). # user + password as separate vault entries (Wave 8 aligned to vault).
PB_PASS="$(cred_raw proton-bridge-imap)" PB_USER="$(cred_raw proton-bridge-imap-user)"
[ -n "$PB_PASS" ] || die "credctl: proton-bridge-imap not set" [ -n "$PB_USER" ] || die "credctl: proton-bridge-imap-user not set"
PB_PASS="$(cred_raw proton-bridge-imap-pass)"
[ -n "$PB_PASS" ] || die "credctl: proton-bridge-imap-pass not set"
export PROTON_BRIDGE_IMAP_USER="$PB_USER"
export PROTON_BRIDGE_IMAP_PASSWORD="$PB_PASS" export PROTON_BRIDGE_IMAP_PASSWORD="$PB_PASS"
exec "$@" exec "$@"
;; ;;
perplexity) perplexity)
# Lightweight WebSearch path. Most Steev research goes through the # Lightweight WebSearch path. Most Steev research goes through the
# perplexity MCP server (which holds its own key); this credbridge entry # perplexity MCP server (which holds its own key); this credbridge entry
# exists for scripts that need a raw key (rare). # exists for scripts that need a raw key (rare). Wave 8 renamed
PPL_KEY="$(cred_raw perplexity-api)" # vault entry `perplexity-api` → `perplexity`.
[ -n "$PPL_KEY" ] || die "credctl: perplexity-api not set" PPL_KEY="$(cred_raw perplexity)"
[ -n "$PPL_KEY" ] || die "credctl: perplexity not set"
export PERPLEXITY_API_KEY="$PPL_KEY" export PERPLEXITY_API_KEY="$PPL_KEY"
exec "$@" exec "$@"
;; ;;
*) *)
die "unknown tool: $TOOL (allowed: google-workspace|proton-bridge|perplexity)" die "unknown tool: $TOOL (allowed: proton-bridge|perplexity)"
;; ;;
esac esac

View File

@ -310,8 +310,72 @@ HOOK_EOF
echo " F4 installed: $HOOK_DST" echo " F4 installed: $HOOK_DST"
fi fi
# F6 — MCP server materialization (Wave 8 Q9)
# Reads manifest.optional_tools (mcp_<server-name-with-underscores> aliases),
# maps to runtime MCP server names (hyphenated), copies global config block
# into per-profile config.yaml. Removes non-declared MCPs (closes bte leak).
if [ "$DRY" = 1 ]; then
echo "DRY: F6 materialize MCP allowlist → $PROFILE_CFG"
elif command -v yq >/dev/null 2>&1 && [ -f "$HERMES_HOME/config.yaml" ]; then
# Declared MCP set (mcp_proton_calendar → proton-calendar etc).
DECLARED_MCPS=$(yq -r '.optional_tools[]?' "$REPO/manifest.yaml" 2>/dev/null | sed 's/^mcp_//; s/_/-/g')
if [ -z "$DECLARED_MCPS" ]; then
echo " F6: no optional_tools declared — skip"
else
mkdir -p "$(dirname "$PROFILE_CFG")"
[ -f "$PROFILE_CFG" ] || : > "$PROFILE_CFG"
F6_ADDED=0; F6_REMOVED=0; F6_MISSING=0
# Set the per-profile mcp_servers block from the declared list. Existing
# entries NOT in declared list are dropped (denylist enforcement).
GLOBAL_CFG="$HERMES_HOME/config.yaml"
python3 - "$GLOBAL_CFG" "$PROFILE_CFG" "$DECLARED_MCPS" <<'PY'
import sys, yaml
gcfg, pcfg, declared_str = sys.argv[1], sys.argv[2], sys.argv[3]
declared = [s.strip() for s in declared_str.splitlines() if s.strip()]
g = yaml.safe_load(open(gcfg).read()) or {}
p = yaml.safe_load(open(pcfg).read()) or {}
g_mcps = g.get('mcp_servers', {}) or {}
new_block = {}
missing = []
for name in declared:
if name in g_mcps:
new_block[name] = g_mcps[name]
else:
missing.append(name)
prev = set((p.get('mcp_servers') or {}).keys())
new = set(new_block.keys())
added = sorted(new - prev)
removed = sorted(prev - new)
p['mcp_servers'] = new_block
open(pcfg, 'w').write(yaml.safe_dump(p, sort_keys=False, allow_unicode=True))
for n in added: print(f" F6 + {n}")
for n in removed: print(f" F6 - {n} (denied)")
for n in missing: print(f" F6 ⚠ {n} (declared but not in global mcp_servers — skipped)")
print(f" F6 wrote mcp_servers: {len(new_block)} entr{'y' if len(new_block)==1 else 'ies'}")
PY
fi
else
echo " WARN: F6 yq/global config missing — skipping MCP materialization"
fi
# F7 — macOS-only externals OS-gate (Wave 8 Q10)
# Reads expected_external_skills entries with os_constraint: darwin and emits
# an INFO line on non-Darwin hosts. No install action (these are external
# prereqs, not provisioned by this installer); annotation is the audit record.
HOST_OS="$(uname -s 2>/dev/null || echo Unknown)"
if [ "$DRY" = 1 ]; then
echo "DRY: F7 OS-gate check (host=$HOST_OS)"
elif command -v yq >/dev/null 2>&1; then
MACOS_ONLY=$(yq -r '.expected_external_skills[] | select(type == "!!map") | select(.os_constraint == "darwin") | .name' "$REPO/manifest.yaml" 2>/dev/null || true)
if [ -n "$MACOS_ONLY" ] && [ "$HOST_OS" != "Darwin" ]; then
echo " F7 INFO: macOS-only externals declared but host=$HOST_OS — unavailable:"
while IFS= read -r s; do [ -n "$s" ] && echo " - $s"; done <<< "$MACOS_ONLY"
fi
fi
echo "" echo ""
echo "== done ==" echo "== done =="
echo " verify skills: hermes -p steev skills list | grep steev-agent" echo " verify skills: hermes -p steev skills list | grep steev-agent"
echo " verify mcp servers: hermes -p steev mcp list"
echo " verify assignee registered: hermes kanban assignees | grep steev" echo " verify assignee registered: hermes kanban assignees | grep steev"
echo " start gateway (when ready): hermes profile gateway start steev" echo " start gateway (when ready): hermes profile gateway start steev"

View File

@ -44,12 +44,16 @@ lib:
# tree (~/.hermes/skills/) or external skill libraries the principal already installed. # tree (~/.hermes/skills/) or external skill libraries the principal already installed.
expected_external_skills: expected_external_skills:
- google-workspace # Gmail + Calendar + Contacts - google-workspace # Gmail + Calendar + Contacts
- apple-notes # macOS-local via osascript
- apple-reminders # macOS-local via osascript
- obsidian # ~/vaults/steev PKM - obsidian # ~/vaults/steev PKM
- himalaya # IMAP/SMTP via proton-bridge sidecar - himalaya # IMAP/SMTP via proton-bridge sidecar
- imessage # macOS-local
- perplexity # WebSearch toolset (lightweight; MCP preferred) - perplexity # WebSearch toolset (lightweight; MCP preferred)
# macOS-only skills (Wave 8 Q10): install.sh F7 emits info on non-Darwin hosts.
- name: apple-notes
os_constraint: darwin
- name: apple-reminders
os_constraint: darwin
- name: imessage
os_constraint: darwin
# MCP servers Steev consumes. Names match runtime-prefixed form (mcp_<server>_<tool>). # MCP servers Steev consumes. Names match runtime-prefixed form (mcp_<server>_<tool>).
optional_tools: optional_tools:
@ -61,15 +65,26 @@ optional_tools:
requires_tools: [terminal, memory_tool] requires_tools: [terminal, memory_tool]
credentials: # validated by validate_access.sh credentials: # validated by validate_access.sh
- name: google-workspace # Wave 8 (2026-05-24): aligned with vault exact-match per DISCLOSURE-SCHEMA §4.5.
purpose: Gmail + Calendar + Contacts read/write for daily briefing + inbox triage # google-workspace removed — builtin manages its own OAuth via Hermes hub (not credctl vault).
- name: proton-bridge-imap-user
purpose: Proton Bridge IMAP/SMTP username (himalaya path)
resolved_via: credbridge.sh resolved_via: credbridge.sh
- name: proton-bridge-imap - name: proton-bridge-imap-pass
purpose: local Proton Bridge IMAP/SMTP password (himalaya path) purpose: Proton Bridge IMAP/SMTP password (himalaya path)
resolved_via: credbridge.sh resolved_via: credbridge.sh
- name: perplexity-api - name: perplexity
purpose: Perplexity API key for raw WebSearch (MCP path preferred) purpose: Perplexity API key for raw WebSearch (MCP path preferred)
resolved_via: credbridge.sh resolved_via: credbridge.sh
- name: proton-account-email
purpose: Proton account email (consumed by proton-email MCP server)
resolved_via: credbridge.sh
- name: proton-account-password
purpose: Proton account password (consumed by proton-email MCP server)
resolved_via: credbridge.sh
- name: proton-mailbox-password
purpose: Proton mailbox E2E key for mail decryption (consumed by proton-email MCP server)
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
@ -140,26 +155,47 @@ disclosure:
justification: "CEO delegation transport — steev → ceo-planb (steev-agent SKILL.md L83)" justification: "CEO delegation transport — steev → ceo-planb (steev-agent SKILL.md L83)"
mcp_servers: [] # DENY-BY-DEFAULT. bte REMOVED (hard-rule fix). mcp_servers: [] # DENY-BY-DEFAULT. bte REMOVED (hard-rule fix).
# proton-* + perplexity MCP installs PENDING JP review # Wave 8 (2026-05-24): install.sh F6 wires the 3 proton MCPs
# (install-gap row in DISCLOSURE.md §12). # (proton-calendar, proton-email, proton-contacts) into per-profile
# runtime config from manifest.optional_tools. mcp_perplexity is
# deferred — server not yet in `hermes mcp list`.
# Per-tool enumeration in disclosure.mcp_servers DEFERRED to
# Wave 8.5 (requires tool introspection per server).
sovereign_apis: [] # 0 direct HTTP/gRPC calls (per audit §3) sovereign_apis: [] # 0 direct HTTP/gRPC calls (per audit §3)
cortex_tools: [] # steev does not consume cortex/L6-* or cortex/PG-* cortex_tools: [] # steev does not consume cortex/L6-* or cortex/PG-*
credentials: credentials:
- vault_name: google-workspace # Wave 8 (2026-05-24) — aligned with vault per DISCLOSURE-SCHEMA §4.5 (exact-match).
# google-workspace removed (Hermes builtin self-manages OAuth, not in credctl vault).
- vault_name: proton-bridge-imap-user
status: required status: required
scope: read-write scope: read
used_by: [credbridge.sh] used_by: [credbridge.sh]
governance: "JP-personal; Gmail+Calendar+Contacts for briefing + inbox triage" governance: "JP-personal; local Proton Bridge IMAP/SMTP username (himalaya path)"
- vault_name: proton-bridge-imap - vault_name: proton-bridge-imap-pass
status: required status: required
scope: read-write scope: read
used_by: [credbridge.sh] used_by: [credbridge.sh]
governance: "JP-personal; local Proton Bridge IMAP/SMTP (himalaya path)" governance: "JP-personal; local Proton Bridge IMAP/SMTP password (himalaya path)"
- vault_name: perplexity-api - vault_name: perplexity
status: optional status: optional
scope: read scope: read
used_by: [credbridge.sh] used_by: [credbridge.sh]
governance: "JP-personal; WebSearch fallback (MCP path preferred)" governance: "JP-personal; WebSearch fallback (MCP path preferred)"
- vault_name: proton-account-email
status: required
scope: read
used_by: [credbridge.sh, mcp_proton_email]
governance: "JP-personal; Proton account email (consumed by proton-email MCP server)"
- vault_name: proton-account-password
status: required
scope: read
used_by: [credbridge.sh, mcp_proton_email]
governance: "JP-personal; Proton account password (consumed by proton-email MCP server)"
- vault_name: proton-mailbox-password
status: required
scope: read
used_by: [credbridge.sh, mcp_proton_email]
governance: "JP-personal; Proton mailbox E2E key for mail decryption"

View File

@ -0,0 +1,91 @@
---
name: proton-tools
description: "When Steev needs to access JP's Proton account — Calendar, Mail, or Contacts. Use this skill to discover which tool answers the user's question, and how to call it. Covers all 24 Proton MCP tools across the three cortex MCP servers (proton-calendar, proton-email, proton-contacts). Triggers: any request involving JP's calendar (events, meetings, availability), mail (inbox, send, reply, search, folders), or contacts (lookup, add, search). Drive is NOT in scope — defer Drive requests."
metadata:
version: 1.0.0
hermes:
requires_mcp_servers: [proton-calendar, proton-email, proton-contacts]
---
# Proton Tools — Calendar + Mail + Contacts
Authoritative reference for the 24 tools exposed by three cortex MCP servers — `proton-calendar` (8 tools), `proton-email` (10 tools), `proton-contacts` (6 tools). Each MCP facade dials a long-running gRPC gate that holds the Proton session.
## Hard rules
- **Drive is out of scope.** If the user asks about Proton Drive files/folders, say so and defer — there is no `drive_*` tool. Roadmap: `rclone-module` MCP wrap.
- **Destructive tools require explicit confirmation.** `email_send`, `email_reply`, `email_forward`, `calendar_delete`, `contacts_delete`. Never call these without quoting back the action + target + asking JP to confirm.
- **Date inputs are ISO 8601** (`2026-05-23T14:00:00-04:00`). Convert relative dates ("tomorrow", "next Tuesday") into ISO before tool call.
- **Pagination**: `email_list`, `calendar_events`, `contacts_list` are paginated. Default page size is small (~20). Fetch additional pages only when the user asks for more.
## When to use which tool
### Calendar (8 tools)
| User intent | Tool |
|---|---|
| "What calendars do I have?" | `calendar_list` |
| "What's on my calendar today/this week?" | `calendar_events` with date range |
| "What's coming up?" "Next few meetings?" | `calendar_upcoming` |
| "Find meetings about X" | `calendar_search` |
| "Show me details of [event]" | `calendar_event_get` |
| "Schedule a meeting with…" | `calendar_create` (confirm first) |
| "Move my 3pm to 4pm" | `calendar_update` |
| "Cancel my 3pm" | `calendar_delete` (DESTRUCTIVE — confirm) |
### Mail (10 tools)
| User intent | Tool |
|---|---|
| "How many unread?" "What folders?" | `email_folders` |
| "Show me my inbox" "Latest emails" | `email_list` (folder=INBOX) |
| "Open that email" | `email_read` by UID |
| "Search inbox for…" | `email_search` |
| "Send an email to…" | `email_send` (DESTRUCTIVE — draft + confirm) |
| "Reply to that" | `email_reply` (DESTRUCTIVE — draft + confirm) |
| "Forward this to…" | `email_forward` (DESTRUCTIVE — confirm) |
| "Archive that" | `email_archive` |
| "Mark as read/unread" | `email_mark_read` / `email_mark_unread` |
### Contacts (6 tools)
| User intent | Tool |
|---|---|
| "Who do I have in contacts?" | `contacts_list` |
| "Look up [person]" | `contacts_search` |
| "Pull up [person]'s details" | `contacts_get` |
| "Add [person] to contacts" | `contacts_create` |
| "Update [person]'s email/phone" | `contacts_update` |
| "Remove [person]" | `contacts_delete` (DESTRUCTIVE — confirm) |
## Daily briefing — tool order
When JP asks for the morning briefing, query in this order:
1. `calendar_upcoming` (hours=24) → events today
2. `email_folders` → unread counts
3. `email_list` (folder=INBOX, limit=10) → recent inbox
4. `email_search` (folder=INBOX, query="from:important-person OR is:flagged") → priorities
Don't dump raw output. Synthesize. Lead with what's actionable in JP's voice.
## Search composition
For broad questions like "anything from [person] this week":
- `email_search` (folder=INBOX, query="from:<person>")
- `calendar_search` (query="<person>")
- `contacts_search` (query="<person>")
Run in parallel. Merge results. Group by source.
## Error handling
- **"WaitReady timeout"** → proton connector still booting. Retry once after 2-3s. If still failing, say so + suggest JP check `hermes mcp test proton`.
- **403 / scope error** → proton session expired. Tool handler should re-auth automatically; if not, JP needs to re-run setup.
- **Network / 5xx** → transient. Retry once. If persistent, report and stop.
## What NOT to do
- Don't paginate aggressively — fetch one page, summarize, ask if JP wants more.
- Don't auto-send drafts. Even after JP says "send" once, re-quote subject + recipient on the next compose.
- Don't synthesize calendar events from email content unless JP explicitly asks ("add this to my calendar").
- Don't enumerate every contact when JP asks "who's [person]" — use search, not list.