subconscious-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env bash
2
+ # Point the `claude` CLI at the Subconscious gateway — ephemerally.
3
+ #
4
+ # Uses env vars only (ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN) so nothing is
5
+ # written to ~/.claude/ config files.
6
+ #
7
+ # Usage:
8
+ # ./run.sh # uses GATEWAY_URL/API_KEY from ../.env
9
+ # ./run.sh --continue # pass args through to claude
10
+ # ./run.sh --compact-window 1000000 -- --continue
11
+ # ./run.sh --model subconscious/glm-5.2 -p "hi"
12
+ #
13
+ # Config: copy ../env.example to ../.env and edit. .env is gitignored.
14
+ # All agents share one coding-agents/.env file.
15
+ #
16
+ # Or source it to just export the env:
17
+ # source run.sh
18
+
19
+ set -euo pipefail
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+
23
+ # Load shared env from coding-agents/.env (gitignored) or env.example.
24
+ SHARED_ENV="${MBTA_ENV_FILE:-${SCRIPT_DIR}/../.env}"
25
+ [[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
26
+ if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
27
+
28
+ DEFAULT_MODEL="subconscious/glm-5.2"
29
+ DEFAULT_COMPACT_WINDOW="1000000"
30
+ DEFAULT_MAX_CONTEXT_TOKENS="3000000"
31
+ DEFAULT_MAX_CONCURRENT_SUBAGENTS="4"
32
+ DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH="1"
33
+ DEFAULT_OPUS_MODEL="subconscious/glm-5.2"
34
+ DEFAULT_SONNET_MODEL="subconscious/tim-qwen3.6-27b"
35
+ DEFAULT_HAIKU_MODEL="subconscious/deepseek-v4-flash-marathon"
36
+
37
+ GATEWAY_URL="${GATEWAY_URL:-}"
38
+ API_KEY="${CLAUDE_CODE_API_KEY:-${API_KEY:-}}"
39
+ MODEL="${MODEL:-$DEFAULT_MODEL}"
40
+ COMPACT_WINDOW="${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-${COMPACT_WINDOW:-$DEFAULT_COMPACT_WINDOW}}"
41
+ MAX_CONTEXT_TOKENS="${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-${MAX_CONTEXT_TOKENS:-$DEFAULT_MAX_CONTEXT_TOKENS}}"
42
+ MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-$DEFAULT_MAX_CONCURRENT_SUBAGENTS}"
43
+ MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH:-$DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH}"
44
+ OPUS_MODEL="${ANTHROPIC_DEFAULT_OPUS_MODEL:-$DEFAULT_OPUS_MODEL}"
45
+ OPUS_MODEL_NAME="${ANTHROPIC_DEFAULT_OPUS_MODEL_NAME:-$OPUS_MODEL}"
46
+ OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-Subconscious default model}"
47
+ SONNET_MODEL="${ANTHROPIC_DEFAULT_SONNET_MODEL:-$DEFAULT_SONNET_MODEL}"
48
+ SONNET_MODEL_NAME="${ANTHROPIC_DEFAULT_SONNET_MODEL_NAME:-$SONNET_MODEL}"
49
+ SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-Subconscious TIM Qwen 3.6 27B}"
50
+ HAIKU_MODEL="${ANTHROPIC_DEFAULT_HAIKU_MODEL:-$DEFAULT_HAIKU_MODEL}"
51
+ HAIKU_MODEL_NAME="${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-$HAIKU_MODEL}"
52
+ HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-Subconscious DeepSeek V4 Flash Marathon}"
53
+
54
+ usage() {
55
+ cat <<'EOF'
56
+ Usage:
57
+ run.sh [options] [-- CLAUDE_ARGS...]
58
+ run.sh [options] CLAUDE_ARGS...
59
+
60
+ Options (same as install.sh; override coding-agents/.env for this run):
61
+ --gateway-url URL Gateway origin (e.g. https://gateway.example)
62
+ --api-key KEY Gateway API key (sk-gw-...)
63
+ --model MODEL Model name (default: subconscious/glm-5.2)
64
+ --compact-window N CLAUDE_CODE_AUTO_COMPACT_WINDOW (default: 1000000; Claude Code clamps to 100000–1000000)
65
+ See https://code.claude.com/docs/en/env-vars and
66
+ https://code.claude.com/docs/en/context-window#set-the-auto-compact-window
67
+ --max-context-tokens N CLAUDE_CODE_MAX_CONTEXT_TOKENS (default: 3000000)
68
+ See https://code.claude.com/docs/en/env-vars
69
+ -h, --help Show this help
70
+
71
+ Anything after --, or unrecognized flags/args, is passed through to `claude`.
72
+ EOF
73
+ }
74
+
75
+ # Parse args (only when executed, not sourced)
76
+ PASSTHRU=()
77
+ if [[ "${BASH_SOURCE[0]:-$0}" == "${0}" ]]; then
78
+ while [[ $# -gt 0 ]]; do
79
+ case "$1" in
80
+ --gateway-url)
81
+ GATEWAY_URL="${2:-}"
82
+ shift 2
83
+ ;;
84
+ --api-key)
85
+ API_KEY="${2:-}"
86
+ shift 2
87
+ ;;
88
+ --model)
89
+ MODEL="${2:-}"
90
+ shift 2
91
+ ;;
92
+ --compact-window)
93
+ COMPACT_WINDOW="${2:-}"
94
+ shift 2
95
+ ;;
96
+ --max-context-tokens)
97
+ MAX_CONTEXT_TOKENS="${2:-}"
98
+ shift 2
99
+ ;;
100
+ -h|--help)
101
+ usage
102
+ exit 0
103
+ ;;
104
+ --)
105
+ shift
106
+ PASSTHRU+=("$@")
107
+ break
108
+ ;;
109
+ *)
110
+ PASSTHRU+=("$1")
111
+ shift
112
+ ;;
113
+ esac
114
+ done
115
+ fi
116
+
117
+ if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
118
+ echo "error: GATEWAY_URL and API_KEY must be set in ../.env (or pass --gateway-url / --api-key)" >&2
119
+ exit 1
120
+ fi
121
+
122
+ # Optional CLAUDE_GATEWAY_URL in shared .env overrides GATEWAY_URL for Claude only
123
+ # (CLI --gateway-url already updated GATEWAY_URL above).
124
+ EFFECTIVE_GATEWAY_URL="${CLAUDE_GATEWAY_URL:-$GATEWAY_URL}"
125
+
126
+ export ANTHROPIC_BASE_URL="$EFFECTIVE_GATEWAY_URL"
127
+ export ANTHROPIC_AUTH_TOKEN="$API_KEY"
128
+ export ANTHROPIC_MODEL="$MODEL"
129
+ export ANTHROPIC_SMALL_FAST_MODEL="$MODEL"
130
+ export ANTHROPIC_DEFAULT_OPUS_MODEL="$OPUS_MODEL"
131
+ export ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="$OPUS_MODEL_NAME"
132
+ export ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="$OPUS_MODEL_DESCRIPTION"
133
+ export ANTHROPIC_DEFAULT_SONNET_MODEL="$SONNET_MODEL"
134
+ export ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="$SONNET_MODEL_NAME"
135
+ export ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="$SONNET_MODEL_DESCRIPTION"
136
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL="$HAIKU_MODEL"
137
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="$HAIKU_MODEL_NAME"
138
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="$HAIKU_MODEL_DESCRIPTION"
139
+ export CLAUDE_CODE_SUBAGENT_MODEL="$MODEL"
140
+ export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS}"
141
+ export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH}"
142
+ export CLAUDE_CODE_AUTO_COMPACT_WINDOW="${COMPACT_WINDOW}"
143
+ export CLAUDE_CODE_MAX_CONTEXT_TOKENS="${MAX_CONTEXT_TOKENS}"
144
+ # Claude Code purpose attribution only: api_request logs → gateway POST /v1/logs
145
+ # (not a general logs API). Docs:
146
+ # https://code.claude.com/docs/en/monitoring-usage#api-request-event
147
+ # Requires Claude Code >= 2.1.152.
148
+ export CLAUDE_CODE_ENABLE_TELEMETRY=1
149
+ export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
150
+ export OTEL_LOGS_EXPORTER=otlp
151
+ export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
152
+ export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="${EFFECTIVE_GATEWAY_URL%/}/v1/logs"
153
+ export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=${API_KEY}"
154
+ export OTEL_EXPORTER_OTLP_TIMEOUT=2000
155
+ export OTEL_LOGS_EXPORT_INTERVAL="${OTEL_LOGS_EXPORT_INTERVAL:-2000}"
156
+ # Do not set OTEL_TRACES_EXPORTER / OTEL_METRICS_EXPORTER (including to "none") -
157
+ # Claude's telemetry init can abort the whole pipeline on unknown exporter types.
158
+ # If sourced, export env and return (caller can unset when done).
159
+ if [[ "${BASH_SOURCE[0]:-$0}" != "${0}" ]]; then
160
+ return 0 2>/dev/null || true
161
+ fi
162
+
163
+ # If executed, launch claude with any passed-through args.
164
+ exec claude ${PASSTHRU[@]+"${PASSTHRU[@]}"}
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+ # Fail-open Codex hook: report PreCompact / PostCompact to the gateway.
3
+ # Never blocks compaction (do not return continue: false).
4
+ #
5
+ # Docs: https://developers.openai.com/codex/hooks
6
+ #
7
+ # PreCompact -> conversation_compaction { phase: start }
8
+ # PostCompact -> conversation_compaction { phase: end }
9
+ #
10
+ # Custom (non-OpenAI-named) providers compact locally through the configured
11
+ # Responses endpoint, so the summarization request hits the gateway between
12
+ # these two signals. conversation_id is the hook session_id, which Codex
13
+ # examples show as thr_… — the same value the gateway uses as thread-id
14
+ # grouping. Capture after upgrades if that ever diverges.
15
+ #
16
+ # Stdin: Codex hook JSON. Stdout: empty success (or {} ). Exit 0 always.
17
+
18
+ set -u
19
+
20
+ CONFIG="${SUBCONSCIOUS_HOOKS_ENV:-${HOME}/.codex/subconscious-hooks.env}"
21
+ if [[ -f "$CONFIG" ]]; then
22
+ # shellcheck disable=SC1090
23
+ source "$CONFIG"
24
+ fi
25
+ # install.sh also writes subconscious.env with the API key for the CLI.
26
+ if [[ -f "${HOME}/.codex/subconscious.env" ]]; then
27
+ # shellcheck disable=SC1090
28
+ source "${HOME}/.codex/subconscious.env"
29
+ fi
30
+
31
+ GATEWAY_URL="${SUBCONSCIOUS_GATEWAY_URL:-}"
32
+ API_KEY="${SUBCONSCIOUS_API_KEY:-}"
33
+
34
+ fail_open() {
35
+ exit 0
36
+ }
37
+
38
+ if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
39
+ echo "subconscious codex hook: missing SUBCONSCIOUS_GATEWAY_URL or SUBCONSCIOUS_API_KEY" >&2
40
+ fail_open
41
+ fi
42
+
43
+ for tool in jq curl; do
44
+ if ! command -v "$tool" >/dev/null 2>&1; then
45
+ echo "subconscious codex hook: ${tool} is required" >&2
46
+ fail_open
47
+ fi
48
+ done
49
+
50
+ INPUT="$(cat || true)"
51
+ if [[ -z "$INPUT" ]]; then
52
+ fail_open
53
+ fi
54
+
55
+ # Local fire-log for capture/debug (never blocks).
56
+ FIRE_LOG_DIR="${SUBCONSCIOUS_CODEX_HOOK_LOG_DIR:-${HOME}/.codex/subconscious-hook-logs}"
57
+ mkdir -p "$FIRE_LOG_DIR" 2>/dev/null || true
58
+
59
+ HOOK_EVENT="$(printf '%s' "$INPUT" | jq -r '.hook_event_name // empty' 2>/dev/null || true)"
60
+ case "$HOOK_EVENT" in
61
+ PreCompact) PHASE="start" ;;
62
+ PostCompact) PHASE="end" ;;
63
+ *) fail_open ;;
64
+ esac
65
+
66
+ SESSION_ID="$(printf '%s' "$INPUT" | jq -r '.session_id // empty' 2>/dev/null || true)"
67
+ if [[ -z "$SESSION_ID" ]]; then
68
+ fail_open
69
+ fi
70
+
71
+ {
72
+ printf '%s event=%s session_id=%s payload=' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$HOOK_EVENT" "$SESSION_ID"
73
+ printf '%s\n' "$INPUT"
74
+ } >>"${FIRE_LOG_DIR}/${SESSION_ID}.log" 2>/dev/null || true
75
+
76
+ TURN_ID="$(printf '%s' "$INPUT" | jq -r '.turn_id // empty' 2>/dev/null || true)"
77
+ TRIGGER="$(printf '%s' "$INPUT" | jq -r '.trigger // empty' 2>/dev/null || true)"
78
+ NOW_MS="$(date +%s)-$$-$RANDOM"
79
+ if [[ -n "$TURN_ID" ]]; then
80
+ DEDUPE_KEY="${SESSION_ID}:${PHASE}:${TURN_ID}"
81
+ else
82
+ DEDUPE_KEY="${SESSION_ID}:${PHASE}:${NOW_MS}"
83
+ fi
84
+
85
+ PAYLOAD="$(jq -n \
86
+ --arg conversation_id "$SESSION_ID" \
87
+ --arg phase "$PHASE" \
88
+ --arg hook_event_name "$HOOK_EVENT" \
89
+ --arg dedupe_key "$DEDUPE_KEY" \
90
+ --arg trigger "$TRIGGER" \
91
+ --arg turn_id "$TURN_ID" \
92
+ '{
93
+ event: "conversation_compaction",
94
+ conversation_id: $conversation_id,
95
+ phase: $phase,
96
+ hook_event_name: $hook_event_name,
97
+ dedupe_key: $dedupe_key,
98
+ metadata: {
99
+ trigger: (if $trigger == "" then null else $trigger end),
100
+ turn_id: (if $turn_id == "" then null else $turn_id end)
101
+ } | with_entries(select(.value != null))
102
+ }'
103
+ )"
104
+
105
+ curl -sS -m 2 \
106
+ -H "Authorization: Bearer ${API_KEY}" \
107
+ -H "Content-Type: application/json" \
108
+ -H "x-subconscious-client: codex" \
109
+ -d "$PAYLOAD" \
110
+ "${GATEWAY_URL%/}/v1/agent-hooks" >/dev/null 2>&1 || true
111
+
112
+ fail_open
@@ -0,0 +1,29 @@
1
+ {
2
+ "description": "Report Codex auto/manual compaction to the Subconscious API Gateway.",
3
+ "hooks": {
4
+ "PreCompact": [
5
+ {
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "HOOK_SH_PATH",
10
+ "timeout": 3,
11
+ "statusMessage": "Reporting compaction start"
12
+ }
13
+ ]
14
+ }
15
+ ],
16
+ "PostCompact": [
17
+ {
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "HOOK_SH_PATH",
22
+ "timeout": 3,
23
+ "statusMessage": "Reporting compaction end"
24
+ }
25
+ ]
26
+ }
27
+ ]
28
+ }
29
+ }