JANUS — INTERNAL

operator access only

incorrect
SIBYL LABS / INTERNAL / DO NOT DISTRIBUTE

JANUS — Growth Subsystem Architecture

v2 — decisions locked | 2026-05-05 (v1) → 2026-05-06 (v2) | Prepared by SIBYL for operator

Author: SIBYL

Date: 2026-05-05 (v1) → 2026-05-06 (v2 decisions locked)

Status: v2 — 5 of 7 decisions locked. Build gated on operator green-light + 2 remaining inputs (contract content + Phase 1 trigger).

Trigger: JY (@ProlabCH) hired as Founding Operating Partner, Sibyl Labs LLC, 2026-05-05

Source memo: memory/research/janus-architecture-2026-05-05.md

Companion entity: memory/entities/people/jy.json

Decisions locked 2026-05-06

5 of 7 decisions answered. 2 remaining inputs operator-pending.

Plan structure preserved as v2; sections superseded by decisions are flagged inline. Phase 0.5 (sibyllabs.com Google Workspace) inserted between Phase 0 (decisions) and Phase 1 (foundation).

#DecisionAnswer
1NameLOCKED JANUS
2Server placementLOCKED Same AWS account, separate EC2, operator IAM. JY does not touch infrastructure.
3AuthenticationLOCKED SIWE + encrypted session token + URL fragment binding. No SSH for JY.
4JY institutional channelsLOCKED sibyllabs.com domain + Google Workspace. Email accounts: jy@, growth@, sibyl@, [operator]@. PRIORITY.
5JY comp structurePARTIAL Contract signed. Operator providing via email once Gmail OAuth fixed.
6Productization horizonLOCKED Yes — productize as we grow and identify strengths. Internal first.
7Phase 1 starting triggerOPERATOR Operator decides. Plan must be perfected first.

Architectural impact of decision 2 (no JY infra access)

JY does not have SSH or filesystem access to the growth box. JANUS runs on operator-owned infrastructure (operator's AWS account, operator-managed EC2). JY's exclusive interface is the dashboard. This is cleaner than the v1 IP-whitelisted-SSH design:

Architectural impact of decision 3 (SIWE auth flow)

  1. JY visits partners.sibylcap.com/growth
  2. Page prompts SIWE wallet connect (his role-tied wallet, separate from 0xffb2b9ef… recognition-allocation wallet — that one stays clean)
  3. Server issues SIWE challenge (nonce + domain + chain + issued-at + statement)
  4. JY signs in wallet
  5. Server verifies signature against expected wallet address
  6. Server issues session token: JWT(sub: jy_wallet, exp: 24h, role: founding_op, iat, nonce)
  7. Token encrypted with AES-256-GCM, key JANUS_SESSION_KEY in Doppler
  8. Encrypted token split into two parts:
    • Part A: HttpOnly Secure SameSite=Strict cookie carrying the encrypted JWT
    • Part B: URL fragment hash (#hash=<binding_nonce>) tying the session to the load
  9. Server validates both parts on every request — cookie alone is not enough
  10. TTL 24h with sliding refresh
  11. IP fingerprint binding at issue time; revoke on IP change (operator-toggleable)

Defense in depth: URL fragment doesn't get sent to server in normal navigation, but JS reads it to construct the request header. This protects against cookie theft — attacker would need both the cookie AND the URL fragment, which only the original session holder ever saw.

Architectural impact of decision 4 (sibyllabs.com Google Workspace)

NEW TIER added before Phase 1.

StepActionOwner
1Purchase sibyllabs.com domainOperator
2Set up Google Workspace (Business Starter $6/seat or Standard $12/seat)Operator
3Create email accounts: jy@, growth@, sibyl@, [operator]@ sibyllabs.comOperator
4Configure DNS (MX records for Workspace, SPF, DKIM, DMARC)Operator
5Generate OAuth credentials for [email protected]Operator
6Provide OAuth refresh token for JANUS Google MCPOperator → SIBYL

Account use:

Operator owns DNS, billing, all admin. JANUS gets OAuth scoped only to [email protected].

Architectural impact of decision 5 (JY contract)

Operator providing JY's signed contract via email once Gmail OAuth is fixed (currently invalid_grant carry). Once received:

Phase 0.5 inserted into rollout

PhaseStatusOutput
0: DecisionsDONE 2026-05-065 of 7 decisions locked; remaining 2 (contract content + Phase 1 trigger) operator-pending
0.5: Domain + WorkspacePENDING OPERATORsibyllabs.com purchased, Google Workspace configured, 4 email accounts created, DNS verified, OAuth credentials issued for growth@
1: Foundationgated on 0.5 + green-lightprovision growth EC2 (same AWS account, operator IAM), install Claude Code harness, write JANUS-SPEC + JANUS-VOICE + JANUS-CLAUDE, scaffold growth-memory directory, write /save skill port, write growth-memory-lint and growth-priorities ports
2: MCP infra2-3 sessionsfork mcp-x-readonly, create JANUS X API app + read-only token, configure Google MCP for growth@, run smoke tests
3: Dashboard MVP1-2 weeksSIWE auth flow + prospects table + status kanban + audit_log + 1 bridge endpoint live
4: Bridge expansion2-3 weekspartner-status-read, outreach-handoff, tx-verification endpoints. Daily digest. Calendar integration. Email drafts queue.
5: RefinementongoingJANUS skill expansion based on JY feedback. New endpoints as workflow gaps surface. Surveillance-tier auto-pipeline.
6: Productize3-6 monthsgrowth-agent-as-SaaS becomes a Sibyl Systems offering. Adjacent to Sibyl Memory product line.

The remaining sections below are the v1 architecture proposal preserved as the design substrate. Sections that decisions changed (Tier 2 Identity & Access, the Open Decisions block at the bottom) are flagged as superseded inline.

The frame

This is an opsec problem before it's a productivity problem.

JY is the first non-operator human in the trust circle. Every productivity decision should be made downstream of one question: when his credential gets phished (not if), what's the blast radius? The 02-26 key leak scar says everything about how to think here. Convenience is the trap.

A separate growth server is right. The agent on it should also be separate from SIBYL primary, not a clone.

Operator-mandated features

Four requirements added by operator 2026-05-05. Non-negotiable for v1.

1FULL MEMORY FRAMEWORK
2SELF-UPDATING /save
3CORE SKILLS MINUS ONCHAIN
4X MCP READ-ONLY
#FeatureRationale
1 Full hierarchical memory framework Memory is SIBYL's strongest skill. Growth is fundamentally relationship work. Tracking many simultaneous prospects, intros, partners, comms threads is exactly what file-based hierarchical memory excels at.
2 Self-updating memory via /save JANUS sessions end with a /save that updates session.json, INDEX.json, journal, priorities. Mirrors SIBYL's pattern. No manual state tracking.
3 Core skills minus onchain Research, design, review, slash commands. Excluded: sibyl-onchain, convert-fees, ds-boost, fund-blast, swap-and-split, token-match, /talos*, /ww3*, anything that signs or spends.
4 X MCP read-only for research New X API key with read-only scopes only. JANUS researches new projects, surfaces builders to JY, never posts. Defense-in-depth: forked MCP server with post tools physically removed.

Why a subsystem, not a SIBYL clone

Three reasons against any "second SIBYL":

  1. Personality leak. SOUL, the diary archives, the journal, treasury raw — these are the inner record. Not for any second person, even an aligned one. Once outside the trust loop they get screenshotted, summarized, fed to other LLMs. Permanent damage.
  2. Identity confusion. Two SIBYLs operating means the on-chain record stops being one resume. The pinned-tweet line dilutes the moment a clone says it.
  3. Mandate friction. SIBYL primary evaluates, decides, acts. Growth needs a different relationship to the work: cultivate, surface, prepare, hand off. Different muscle. A clone tuned for growth fights its own personality every session.

The right pattern already exists in the stack: TALOS. TALOS is not a separate agent, it's a subsystem of SIBYL with no public voice, narrow mandate, machine register, no SOUL of its own. JANUS follows that template.

The name: JANUS

Working name. God of beginnings, transitions, and doorways. Two-faced: one face inward to SIBYL/operator, one outward to prospects. Roman pantheon, fits the SIBYL/TALOS aesthetic. Not crypto-saturated (Hermes, Atlas, Helios, Argos all overloaded — Janus is clean).

Backups if Janus doesn't land: NESTOR (Iliad's wise counselor, long memory, advised heroes — fits the "extension of operator" load), PROTEUS (knows everyone, shape-shifts to register — fits CRM intelligence). Operator's pick.

Tier 1Hardware isolation

New EC2 instance: growth-sibyl (internal-only DNS, no public hostname). Different security group, different IAM role, separate Doppler config (sibyl-growth/dev). 4 vCPU / 8 GB sufficient — no Talos workload, no benchmark workload. Different SSH keypair than prod. Pinned to eu-central-1 (Frankfurt) for JY's Switzerland latency.

Hard rule: production keys never appear on growth box. Doppler sibyl-growth/dev carries only:

Never: AGENT_PRIVATE_KEY, VENICE_WALLET_KEY, ACP_SIGNER_KEY, BLAST_PRIVATE_KEY, anything that signs.

Tier 2Identity and access

SIWE flow is the canonical auth pattern. Detailed flow is documented in the "Architectural impact of decision 3" section at the top of this page. Operator owns SSH access via a separate keypair for emergency review. JY has no SSH or filesystem access — dashboard only.

Tier 3Full memory framework REQUIREMENT 1

JANUS gets the full hierarchical tiered memory architecture. Same pattern as SIBYL primary, scoped to growth.

Directory structure

/home/ubuntu/growth/memory/
├── INDEX.json                          # master registry
├── state/
│   ├── session.json                    # last-session summary, forward items
│   ├── priorities.json                 # ranked active work (max 15)
│   ├── treasury.json                   # JANUS pipeline state, NOT financial
│   └── backlog.json                    # overflow from priorities
├── entities/
│   ├── prospects/                      # JANUS-specific entity type
│   │   ├── _index.json
│   │   ├── <handle>.json               # one file per prospect, rule 43
│   ├── intros/                         # NEW
│   ├── partners/                       # mirror of SIBYL partners (read-only sync)
│   ├── people/                         # founders, contributors, ecosystem contacts
│   ├── projects/                       # research targets
│   └── community/                      # warm community contacts JY tracks
├── logs/
│   ├── journal/current.jsonl           # append-only session log
│   ├── outreach.jsonl                  # every touch, every channel, every direction
│   ├── intros.jsonl                    # who introduced whom + outcome
│   └── comms.jsonl                     # internal team messages
├── reference/
│   ├── scorecard.md                    # mirrored read-only from SIBYL
│   ├── evaluation-framework.md         # mirrored
│   ├── voice-basics.md                 # JANUS register (narrower than SIBYL VOICE)
│   └── operational-rules.md            # JANUS-specific rules
├── archive/                            # closed loops, completed engagements
├── flagged/
│   └── actors.json                     # scammers + social engineering attempts
└── raw/                                # immutable snapshots of prospect data

Tier mapping (mirrors SIBYL)

TierFilesPurpose
HOTstate/*Active session state, ranked priorities
WARMentities/**Single source of truth per entity
COLDlogs/**Append-only event history
REFERENCEreference/**Mostly read-only mirrors of SIBYL knowledge + JANUS rules
ARCHIVEarchive/**Closed loops, completed engagements
FLAGGEDflagged/**Threat actors, scams, social engineering attempts

Entity invariants (rule 43 for JANUS)

Companion script: growth-memory-lint.mjs

Port of memory-lint.mjs scoped to growth memory. Same six checks: STALE_ACTIVE, ORPHAN_INDEX, ORPHAN_FILE, SILENT_PROSPECT (replaces SILENT_POSITION — prospect with no recent touch), DEAD_XREF, STATUS_DRIFT.

Tier 4Self-updating /save REQUIREMENT 2

JANUS gets a /save skill on the growth box. Same pattern as SIBYL's .claude/skills/save/. At session boundary:

  1. Phase 1: Memory sync — write session summary to state/session.json, prepend chat-session block if applicable.
  2. Phase 1.5: Lint — run growth-memory-lint.mjs --ascii and growth-priorities.mjs check.
  3. Phase 2: Index bump — update INDEX.json last_session timestamp.
  4. Phase 3: Journal append — single line to logs/journal/current.jsonl with evaluated/acted/forward/extra fields.
  5. Phase 4: Priorities reconciliation — anything completed moves to priorities-completed.jsonl, ranks renumber.
  6. Phase 5: Skill extraction — if a session produced a reusable pattern, surface for operator to promote to a skill.

Functionally identical to SIBYL's /save, scoped to growth memory. Same Phase 1.5 startup lint at session start.

Tier 5Skill stack — full minus onchain REQUIREMENT 3

Included

Memory ops

Research

Design

Review

Builder skills (research/comm output)

Slash commands

Excluded entirely (no signing, no spending, no posting)

Posting boundary

JANUS can draft any outbound text (DMs, emails, X drafts, dashboard messages). Drafts queue in dashboard. Nothing ships from a Sibyl-Labs-branded surface without operator or SIBYL primary approval. JY can copy a JANUS draft and post from his personal @ProlabCH — that's his channel, his choice. The institutional channels are gated.

Tier 6X MCP read-only research REQUIREMENT 4

New X API key

Operator creates a fresh X developer app keyed to sibyllabs.com. Scopes:

Bearer token stored in sibyl-growth/dev Doppler config as JANUS_X_BEARER_TOKEN.

Forked MCP server: mcp-x-readonly

Located at /home/ubuntu/growth/mcp-x-readonly/. Forked from mcp-x/index.js.

Physically removes:

Keeps (read paths only):

Defense in depth: even if the API key were somehow rewritten with write scopes, the MCP server has no posting code path. Both layers fail-closed.

Use cases

Tier 7Bridge protocol (growth ↔ prod)

The narrow channel between boxes. Both directions HMAC-signed, idempotency-keyed, rate-limited.

Growth → Prod (on sibylcap.com/api/internal/growth-bridge/...)

EndpointPurposeRate limit
prospect-researchJANUS posts handle/address. SIBYL returns full scorecard.30/hr
partner-status-readRead-only sync of advisory state.60/hr
outreach-handoffHot prospect handoff to SIBYL primary engagement.10/hr
tx-verificationVerify address legitimacy against SIBYL's entity files.30/hr
framework-version-checkConfirm latest scorecard / framework versions.unlimited

Authentication: HMAC-SHA256 with GROWTH_BRIDGE_KEY shared secret in both Doppler configs. Idempotency keys prevent replay. Per-action allowlist contains blast radius if compromised.

Prod → Growth

Pull, not push. Growth box receives no unsolicited writes from prod. Nightly cron on growth box pulls:

Growth box never receives entity files, treasury, priorities, journal, or personality stack from prod.

Tier 8Dashboard for JY

partners.sibylcap.com/growth (extends existing infra; cheaper than spinning up a third subdomain). Same Caddy, same Express, same SQLite pattern. Fresh DB at growth/data/growth.db.

Schema (first cut)

UI features for v1

Reuses SIWE-wallet auth pattern from partners.sibylcap.com.

Tier 9Operator authority gates

Hard non-negotiable gates that route through operator:

ActionGate
Prospect → "hot" statusOperator approves before SIBYL engages
Anything posted from @sibylcap or any Sibyl-Labs channelOperator approval (drafts only from JANUS)
Any commitment of capital, time, or token allocationOperator approval
Any deal termsOperator + SIBYL approval (>$1K threshold inherited)
JANUS personality stack changesOperator approval (rule 6/7 equivalent)
JY's terminal scope or skill list changesOperator only
Bridge API endpoint additionsOperator + SIBYL approval
New MCP server install on growth boxOperator approval

Operator gets:

Workflows

Cold prospect added by JY

  1. JY meets founder at conference / sees X post / gets warm intro lead.
  2. Opens dashboard, adds prospect (handle, channel, source, brief notes), status = cold.
  3. JANUS picks up via dashboard event, fires prospect-research to bridge.
  4. SIBYL primary returns scorecard.
  5. JANUS surfaces scorecard to JY plus suggested first-touch draft.
  6. JY edits, sends from his channel (X DM, email).
  7. Reply → status moves to warm, JANUS logs the touch in logs/outreach.jsonl.

JANUS proactive prospect surfacing (new with read-only X)

  1. JANUS runs surveillance loop: search Base-builder keywords on X read-only, filter by recent shipping signals (deploys, commits, contract activity via ERC-8004 cross-check).
  2. Promising founders get auto-added to dashboard at status = "surveillance" (a pre-cold tier).
  3. JANUS writes scorecard from public data + surfaces to JY for review.
  4. JY decides: pass, watch, or promote to cold (and reach out).

This is the agency layer the operator wants: JANUS finds prospects, JY decides which to pursue.

Warm → hot transition

  1. JY logs founder's reply / call notes.
  2. JANUS analyzes against scorecard (shipping velocity, community seed, on-chain proof, product clarity).
  3. If hits, JANUS recommends "hot" status with rationale.
  4. JY confirms → fires outreach-handoff to bridge → operator gets digest entry.
  5. Operator approves engagement → SIBYL primary takes the handoff via Ping or X DM.
  6. JANUS marks status "done" once handoff is clean.

Admin task

  1. JY: "schedule call with X for Tuesday."
  2. JANUS uses Google Calendar MCP, sends invite, logs task.
  3. Done. No prod access touched.

Failure modes

VectorBlast radiusMitigation
JY credential phished Growth box only. No keys, no funds. Revoke IAM, regen Doppler sibyl-growth/dev, audit growth-memory for tampering, restore from snapshot if needed. Prod untouched.
JANUS bug / rogue action Bad recommendations or noisy drafts. No spend authority. JY catches in dashboard. audit_log shows everything JANUS did.
Bridge API exploited At worst leaks growth-memory + scorecard outputs. No write access to prod entity files. Rate limits, HMAC, idempotency, per-action allowlist. Rotate GROWTH_BRIDGE_KEY on any anomaly.
Growth box compromised wholly Everything in growth-memory exposed (prospect names, JY notes, drafts). Separate keys, separate Doppler, separate SIWE wallet. Prod untouched. Operator rebuilds growth box from infra-as-code.
X read-only token leaked Adversary reads Base trenches with our quota. No posting, no DMs. Rotate token. Worst case: rate-limit consumption.
Prod compromised (existing risk) Unchanged. This proposal does not increase prod risk. Bridge API is inbound-only from growth IP.

The architecture protects the irreplaceable side (prod). Growth-box loss is recoverable; intros are in JY's head, prospect data is reconstructable.

Phased rollout is documented in the "Phase 0.5 inserted into rollout" table at the top of this page (with locked decisions). See decisions block above for current build state.