Skip to content

Commit c6f6cf9

Browse files
author
Joe Roberts
committed
Merge polish/3.2.2-onboarding: add octopoda-init CLI for one-command setup
2 parents 13d6c48 + 2e4d411 commit c6f6cf9

7 files changed

Lines changed: 120 additions & 15 deletions

File tree

README.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,17 @@ pip install octopoda
6969
```python
7070
from octopoda import AgentRuntime
7171

72-
agent = AgentRuntime("my_agent")
73-
agent.remember("user_pref", "dark mode")
72+
agent = AgentRuntime("my_chatbot")
73+
agent.remember("user_name", "Alice")
7474

75-
print(agent.recall("user_pref").value)
76-
# 'dark mode' — still returns after a restart, a deploy, or a process crash.
75+
# kill the process. restart Python. then:
76+
print(agent.recall("user_name").value)
77+
# 'Alice' — still there. Survives every restart, deploy, and crash.
7778
```
7879

7980
That is the entire setup. Your agent now has persistent memory, loop detection, crash recovery, and an audit trail. No config, no Docker, no Redis, no extra services.
8081

81-
### Want the dashboard?
82+
### Want the local dashboard?
8283

8384
```bash
8485
pip install octopoda[server]
@@ -87,14 +88,29 @@ octopoda
8788

8889
Open **http://localhost:7842** — the same dashboard as the cloud version, running against your local data. No account, no API key.
8990

90-
### Want cloud sync?
91+
### Want cloud sync + a hosted dashboard?
9192

92-
Free at [octopodas.com](https://octopodas.com). Set the API key, same code, multi-device sync, team access.
93+
One command after install:
94+
95+
```bash
96+
octopoda-init
97+
```
98+
99+
It walks you through: paste an API key (or sign up free at [octopodas.com](https://octopodas.com)), validates it, and saves it to `~/.octopoda/config.json`. No environment variables to set, no shell config to edit. The SDK auto-loads the key on next import.
100+
101+
After `octopoda-init`, the same Python code above writes to the cloud and shows up live at [octopodas.com/dashboard](https://octopodas.com/dashboard).
102+
103+
<details>
104+
<summary>Prefer environment variables?</summary>
93105

94106
```bash
95107
export OCTOPODA_API_KEY=sk-octopoda-...
96108
```
97109

110+
Both methods work. The SDK checks the env var first, then the config file.
111+
112+
</details>
113+
98114
---
99115

100116
## Local vs Cloud — same code, your choice

octopoda/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
result = agent.recall("key")
1111
"""
1212

13-
__version__ = "3.2.1"
13+
__version__ = "3.2.2"
1414

1515
# Cloud SDK (the main developer-facing API)
1616
from synrix.cloud import Octopoda, Agent, OctopodaError, AuthError, RateLimitError

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "octopoda"
7-
version = "3.2.1"
7+
version = "3.2.2"
88
description = "Persistent Memory Kernel for AI Agents — crash recovery, shared memory, audit trail, real-time dashboard"
99
readme = "README.md"
1010
requires-python = ">=3.9"
@@ -108,6 +108,7 @@ Changelog = "https://github.com/RyjoxTechnologies/Octopoda-OS/blob/main/CHANGELO
108108
octopoda = "synrix_runtime.start:main"
109109
octopoda-mcp = "synrix_runtime.api.mcp_server:main"
110110
octopoda-login = "synrix_runtime.auth_flow:_cli_login"
111+
octopoda-init = "synrix_runtime.auth_flow:_cli_init"
111112

112113
[tool.setuptools.packages.find]
113114
where = ["."]

synrix/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
logger = logging.getLogger(__name__)
1010

1111

12-
__version__ = "3.2.1"
12+
__version__ = "3.2.2"
1313

1414
import os
1515
import warnings

synrix_runtime/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Synrix Agent Runtime — Persistent Memory Kernel for AI Agents
33
"""
44

5-
__version__ = "3.2.1"
5+
__version__ = "3.2.2"
66

77
from synrix_runtime.api.runtime import AgentRuntime
88

synrix_runtime/api/runtime.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,8 @@ def __init__(self, agent_id: str, agent_type: str = "generic", metadata: dict =
286286
AgentRuntime._local_hint_shown = True
287287
if os.environ.get("OCTOPODA_QUIET", "").strip().lower() not in ("1", "true", "yes"):
288288
print(f"Octopoda running locally (SQLite). "
289-
f"For cloud sync + dashboard: https://octopodas.com/signup")
289+
f"For cloud sync + dashboard: run `octopoda-init` "
290+
f"(or sign up at https://octopodas.com)")
290291

291292
def remember(self, key: str, value: Any, tags: list = None) -> MemoryResult:
292293
"""Store a memory in Synrix.

synrix_runtime/auth_flow.py

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,9 @@ def ensure_authenticated(allow_local: bool = False) -> str:
358358
ensure_authenticated._warned = True
359359
if os.environ.get("OCTOPODA_QUIET", "").strip().lower() not in ("1", "true", "yes"):
360360
logger.warning(
361-
"No Octopoda API key found. Set OCTOPODA_API_KEY environment variable "
362-
"or run interactively to sign up. Running in local mode. "
363-
"Sign up free at https://octopodas.com"
361+
"No Octopoda API key found. Running in local mode (SQLite). "
362+
"For cloud sync + dashboard, run: octopoda-init "
363+
"(or sign up free at https://octopodas.com)"
364364
)
365365

366366
# Helpful nudge if an obvious typo of OCTOPODA_API_KEY is set (audit §3.5).
@@ -400,6 +400,93 @@ def _cli_login():
400400
print(" No account configured. Try again with: octopoda-login")
401401

402402

403+
def _cli_init():
404+
"""CLI entry point for `octopoda init` — the recommended onboarding flow.
405+
406+
Cleaner than `octopoda-login` for first-time users: skips the 3-way
407+
signup/login/manual choice menu and offers a single clear path —
408+
"paste an API key, or open the signup page in your browser."
409+
410+
Once the key is validated, it's saved to ~/.octopoda/config.json so the
411+
SDK auto-loads it. No env var setup required.
412+
"""
413+
print()
414+
print("=" * 60)
415+
print(" Octopoda Setup")
416+
print("=" * 60)
417+
print()
418+
419+
# If already authenticated, show status and exit gracefully.
420+
existing = get_api_key()
421+
if existing:
422+
print(f" Already configured.")
423+
print(f" Key: {existing[:20]}...")
424+
print(f" Config: {CONFIG_FILE}")
425+
print()
426+
valid = validate_key(existing)
427+
print(f" Key valid: {'Yes' if valid else 'No (expired or revoked)'}")
428+
print()
429+
if valid:
430+
print(" You're ready to go. Try:")
431+
print()
432+
print(" python -c \"from octopoda import AgentRuntime; "
433+
"a=AgentRuntime('my_agent'); a.remember('hi', 'world'); "
434+
"print(a.recall('hi').value)\"")
435+
print()
436+
print(" Or to re-login with a different account:")
437+
print(" octopoda-login")
438+
print()
439+
return existing
440+
441+
# Not yet authenticated — single clear path.
442+
print(" Welcome. Let's connect your Octopoda account.")
443+
print()
444+
print(" Don't have an API key yet?")
445+
print(" Sign up free at: https://octopodas.com/signup")
446+
print(" (Takes 30 seconds. Then come back and paste your key below.)")
447+
print()
448+
try:
449+
key = input(" Paste your API key (or press Enter to skip): ").strip()
450+
except (EOFError, KeyboardInterrupt):
451+
print("\n Cancelled. Octopoda will run in local mode.")
452+
return ""
453+
454+
if not key:
455+
print()
456+
print(" Skipped. Octopoda will run in local mode (SQLite).")
457+
print(" When ready, run: octopoda-init")
458+
print()
459+
return ""
460+
461+
if not key.startswith("sk-octopoda-"):
462+
print()
463+
print(" That doesn't look like an Octopoda API key.")
464+
print(" Cloud keys start with 'sk-octopoda-'. Try again with: octopoda-init")
465+
print()
466+
return ""
467+
468+
print()
469+
print(" Validating key...")
470+
if not validate_key(key):
471+
print(" Key is invalid or expired. Try again with: octopoda-init")
472+
print(" Or get a fresh key at: https://octopodas.com/dashboard/settings")
473+
print()
474+
return ""
475+
476+
save_api_key(key)
477+
print(f" [OK] Key saved to {CONFIG_FILE}")
478+
print()
479+
print(" You're all set. Try this:")
480+
print()
481+
print(" python -c \"from octopoda import AgentRuntime; "
482+
"a=AgentRuntime('my_agent'); a.remember('hi', 'world'); "
483+
"print(a.recall('hi').value)\"")
484+
print()
485+
print(" Your agent will show up live at: https://octopodas.com/dashboard")
486+
print()
487+
return key
488+
489+
403490
def _cli_status():
404491
"""Show current auth status."""
405492
key = get_api_key()

0 commit comments

Comments
 (0)