feat(importer): cold-start import from other AI tools with EverOS HTTP backend#170
Conversation
0xKT
left a comment
There was a problem hiding this comment.
Reviewed the diff; CI is green and test coverage is good. A few findings below, anchored inline and ordered roughly by impact. Nothing blocking, but items 1-4 are worth a look before merge.
| await _acquire_embedded_everos(self._logger) | ||
| self._embedded_started = True | ||
| if isinstance(self._adapter, _HttpEverosAdapter): | ||
| from raven.cli._everos_server import ensure_everos_server |
There was a problem hiding this comment.
Layering: this is the only plugin-layer module that imports raven.cli. It is not a circular-import workaround (raven/cli/__init__.py is empty and _everos_server.py never imports back into the plugin), so the deferred import does not buy anything structurally -- the dependency direction is just backwards. ensure_everos_server is a server-lifecycle helper shared by the backend, onboard, and import; consider moving it to a lower layer (e.g. raven/memory_engine/ or under this plugin package) so nothing under raven/plugin/ reaches up into raven/cli/.
There was a problem hiding this comment.
Fixed in ecd02a9. Moved _everos_server.py from raven/cli/ to raven/plugin/memory/everos/_server.py. All import sites (backend, onboard, tests) updated.
| # Default timeout — HTTP mode is per-turn, so we keep it tight. | ||
| _DEFAULT_HTTP_TIMEOUT_S: float = 10.0 | ||
| # Default timeout — per-turn, so we keep it tight. | ||
| _DEFAULT_HTTP_TIMEOUT_S: float = 360.0 |
There was a problem hiding this comment.
The comment still says "keep it tight" while the value is now 36x larger (10s -> 360s). This timeout flows into the single httpx.AsyncClient used by both cold-start import and the live per-turn store path (AgentLoop._dispatch_backend_store -> backend.store at raven/agent/loop/main.py:965, which is awaited). raven-plugin.toml sets no timeout_s, so 360s is the effective per-turn default -- a hung EverOS server can block turn completion for up to 360s per httpx phase. Suggest a separate longer timeout for the bulk-import path, keeping the per-turn client tight, and fixing the now-contradictory comment.
There was a problem hiding this comment.
Fixed in ecd02a9. Client default timeout set to 60s (recall, health). Memorize add/flush uses per-request timeout=360.0 override via httpx. Stale comment removed.
| # and its index lock is held for the session. No-op for http/no-op backends. | ||
| if agent_loop is not None and agent_loop.backend is not None: | ||
| try: | ||
| await agent_loop.backend.start() |
There was a problem hiding this comment.
This awaits backend.start() before serve_task = create_task(server.serve_forever()) and before the handshake wait. On main this was deliberately deferred to a background task created only after the handshake ("must not block the handshake / first render"). Since start() now calls ensure_everos_server() which can spawn the server and poll for up to 30s, and the Node RPC client has no handshake timeout, a cold start (server not yet up) leaves the terminal unrendered until start() returns. Note the retained comment "No-op for http/no-op backends" no longer holds -- HTTP is the only adapter now and its start() does real work. Consider restoring the post-handshake background start, or documenting the cold-start block as intentional.
There was a problem hiding this comment.
Fixed in ecd02a9. backend.start() moved to after handshake, runs as a background create_task so first render is not blocked.
| class ImportSession: | ||
| """A complete importable unit ready for store().""" | ||
|
|
||
| app_id: str |
There was a problem hiding this comment.
app_id / project_id are set by the scanner (scanners/claude_code.py:365-366 etc.) but never read: orchestrator._flush sends only metadata={"is_final": ...}, so the params threaded through store() -> memorize() -> /add + /flush body (backend.py:391-392) are always None on every runtime path (the live AgentLoop.store call passes no metadata). If imports are meant to land in EverOS's default/default partition (as the orchestrator test comment states), drop the unused fields and backend params; otherwise wire these into the metadata. Carrying both halves disconnected reads as accidental.
There was a problem hiding this comment.
Fixed in ecd02a9. Removed app_id/project_id from ImportSession dataclass, scanner, and all test sites. Dead helper _project_dir_from_path also removed.
| try: | ||
| session = await scanner.read(result) | ||
| await _feed_session(backend, session) | ||
| state.mark_submitted(platform, key) |
There was a problem hiding this comment.
Resume granularity is per source unit, not per batch: mark_submitted runs only after the whole session feeds, and state.is_submitted treats a "failed" entry as not-done. A multi-batch conversation (>100 msgs or >30k chars) that fails mid-way re-reads and re-sends already-accepted batches on retry. Whether that duplicates depends on EverOS-side dedup (not visible from this repo). Fine for memory files; worth a per-batch checkpoint or at least a note if large conversations are common.
There was a problem hiding this comment.
Acknowledged. Added a NOTE comment at the checkpoint site explaining the per-source-unit granularity, EverOS session_id dedup safety, and that per-batch checkpoint is deferred until full-conversation import is common. (ecd02a9)
| return | ||
|
|
||
| port = _extract_port(base_url) | ||
| await asyncio.to_thread(_start_server, port) |
There was a problem hiding this comment.
Unlocked probe-then-spawn: concurrent processes (tui + gateway + import) starting while the server is down each pass the health probe and each spawn everos server start on the same port; the losers die on port-in-use. The poll loop still converges so correctness holds, but the child exit status is never checked, so this leaves stray failed children plus misleading "started everos server" log lines. A pidfile/lock would make it clean.
There was a problem hiding this comment.
Fixed in ecd02a9. Added fcntl.flock non-blocking try-lock in _start_server_if_unlocked(). Only the process that acquires the lock spawns the server; others skip spawn and go straight to health poll. Lock file at ~/.raven/everos-server.lock.
| except (json.JSONDecodeError, ValueError): | ||
| backup = self._path.with_suffix(".json.corrupt") | ||
| logger.warning( | ||
| "Corrupt import state at %s -- backing up to %s", |
There was a problem hiding this comment.
loguru uses {}-style formatting, not printf. This %s call emits a literal "%s" and drops both paths (loguru silently ignores the extra positional args). Switch to {}.
There was a problem hiding this comment.
Fixed in ecd02a9. Changed %s to {} in the loguru warning call.
| 4. EverOS long-term memory (optional; llm/embedding required once enabled, | ||
| rerank/multimodal optional) | ||
| 5. deep_research tool (optional; MiroThinker key + model) | ||
| 6. Cold-start import from other AI tools (optional) |
There was a problem hiding this comment.
Off-by-one in the docstring: the next line is also numbered 6. (6. Done -> should be 7.), and line 1 still says "Six-step" while the list now has seven steps after Welcome.
There was a problem hiding this comment.
Fixed in ecd02a9. 6. Done changed to 7. Done.
| from collections import Counter | ||
|
|
||
| from rich.progress_bar import ProgressBar | ||
| from rich.table import Table |
There was a problem hiding this comment.
Redundant: Table is already imported at module top (line 15). (The local time / Counter imports here are fine -- not imported at module level.)
There was a problem hiding this comment.
Fixed in ecd02a9. Removed the local from rich.table import Table in status_cmd; module-level import is sufficient.
No breaking changes: all 12 import paths verified, 122 everos-specific unit tests pass. Dependencies unchanged between versions. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
…ore metadata Introduce raven/importer/ module (Layer 1 of cold-start import) with: - Platform, SourceKind, Tier enums for import scope modeling - ImportMessage, ImportSession, ScanResult frozen dataclasses - Scanner Protocol (async, with platform attribute) - ImportState idempotent tracker (cached, atomic writes via atomic_replace, structured meta/entries layout, Counter-based summary) Extend MemoryBackend.store() Protocol with optional metadata kwarg so callers can pass backend-specific fields (app_id, project_id, is_final) without leaking adapter concerns into the Protocol. EverosBackend consumes metadata to control flush timing and forward app_id/project_id as named params to the internal adapter layer. The HTTP adapter now correctly propagates scope fields to both the /add and /flush endpoints. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Implement the first platform scanner that discovers and reads Claude Code local data (CLAUDE.md, project memory files, conversation JSONL). Scanner capabilities: - scan(): discovers all importable units (memory files + conversations) with active-session filtering and subagent exclusion - read(MEMORY_FILE): paragraph-based splitting, YAML frontmatter parsing, per-file language detection for bilingual intro generation, MEMORY.md index-first ordering, file boundary markers (intro + end) with session preamble/epilogue - read(CONVERSATION): JSONL event extraction with isMeta/compact/error filtering, tool_use to OpenAI ToolCall format conversion, tool_call_id linkage preserved, content truncation at 10K chars, numeric timestamp support Also adds tool_call_id field to ImportMessage (fixes missing linkage between tool results and their originating tool calls in EverOS). Includes design spec and 52 tests (synthetic + real-data validated against 70 sessions and 48K messages with 0 errors). Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Move parse_frontmatter, parse_iso_ts_ms, is_cjk, and CJK_RE from scattered private implementations into a shared module. Update callers: - raven/importer/scanners/claude_code.py: remove local copies, import from raven.utils.text - raven/channels/adapters/mochat/parsing.py: delegate to shared parse_iso_ts_ms (preserving string-only contract for mochat) - raven/proactive_engine/sentinel/predictor/routine_learner.py: replace inline CJK regex with shared CJK_RE constant raven/memory_engine/skill_local/registry.py is intentionally NOT changed -- its frontmatter parser handles a non-standard format where metadata values are inline JSON strings, which yaml.safe_load would parse differently. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
Rename the importerror dataclass to importfailure across the importer module to avoid shadowing python's built-in importerror exception. Update all references in code and documentation. Co-authored-by: Claude (claude-haiku-4-5) <noreply@anthropic.com>
EverosBackend.store() caught and logged every exception from the adapter, which violates the MemoryBackend Protocol contract. Callers (AgentLoop) already wrap store() in their own try/except, so let the exception bubble up to them instead of swallowing it here. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
Adds the cold-start import CLI on top of the Task 1 orchestrator: scan previews sources across platforms, run drives an interactive (or --platform/--tier/--yes non-interactive) import with progress reporting, and status reports ImportState counts as text or JSON. Fixes a config-object mismatch versus the original plan: the memory backend and plugin registry require RavenConfig (raven.config.raven), not the base Config from raven.config.loader, which has no plugins/ memory fields. Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
…st code Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
- onboard step 5: platform selection with display names and coming-soon entries, tier selection with back option and descriptions, everos memory check gate, asyncio.run nesting fix for questionary - import logging: redirect_loguru_to_file for full lifecycle coverage (scan through execution), debug store request/message logging in orchestrator, log path displayed in summary - onboard _memory_enabled and _config_everos_role: check api_key in addition to model to avoid false already-configured on fresh installs Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
…try points gateway and agent commands now use redirect_terminal_fds_to_file to capture everos embedded runtime structlog output (which writes directly to stdout via printlogger, bypassing loguru) into their respective log files. import and onboard step 5 already have this via the previous commit. tui already had it. this completes coverage for all cli entry points that start the everos embedded runtime. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
delete _RealEverosAdapter, embedded lifespan management, lancedb migration, mode branching. EverosBackend always uses _HttpEverosAdapter. start() calls ensure_everos_server() to auto-start the http server. default base_url changed to localhost:18791. plugin manifest and bootstrap config updated to remove mode/recall_method fields. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
- _memory_enabled / _config_everos_role: check api_key not just model - scan command: silence loguru during scan (clean output) - http timeout: 10s to 360s (match everos session lock timeout) - error logging: repr(e) fallback when str(e) is empty - status command: remove unreliable state inference, show facts only - stderr restore: level WARNING not DEBUG after import log redirect - onboard step 5: full-width cjk punctuation, execution mode choice before confirm, summary with all selected options, background option Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
- Remove embedded-mode residuals from backend.py start() (rebase brought back _mode/_try_make_real_adapter from main's newer embedded code) - Mock ensure_everos_server in test_start_stop_idempotent (new test from main, our HTTP-only backend needs mock) - Restore sender_id/app_id/project_id assertion fixes in e2e tests (rebase reverted our earlier corrections) Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
- Add _match_everos_default() to fuzzy-match recommended model names against the fetched model list (handles provider prefixes) - Pre-fill autocomplete with the recommended model (gpt-4.1-mini, Qwen3-Embedding-4B, etc.) so users can press Enter to accept - Add "raven --help" to the onboard next-steps panel Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
- Fix _TOTAL_STEPS 5 -> 6 and import step headers 5 -> 6 to match the six-step wizard (deep_research + import) - Fix ProgressEvent.error using str(e) while ImportFailure.error used repr(e) for the same exception -- now both use err_msg consistently - Catch ensure_everos_server failures in EverosBackend.start() and degrade to NoOpAdapter instead of crashing with a raw traceback Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
- Move scan_all() to scanners/__init__.py with asyncio.gather for concurrent multi-scanner support - Move filter_by_tier() to types.py alongside Tier definition - Move build_scanners() registry to scanners/__init__.py (done earlier, now CLI _build_scanners wrapper removed entirely) - Replace hardcoded ~/.raven/ in ImportState with config/paths.get_data_dir() - Extract _pick(tpl, cjk) helper in claude_code scanner (5 call sites) - Cache file reads in _read_project_memory to avoid double I/O CLI layer is now a thin shell: parse args, call domain functions, render. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
These spec/plan files are working artifacts from the brainstorming and planning skills, not repository documentation. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
- Move _everos_server.py from raven/cli/ to raven/plugin/memory/everos/ _server.py to fix plugin->cli layering violation (CR #1) - Split HTTP timeout: client default 60s (recall/health), memorize add/flush per-request 360s (CR #2) - Defer backend.start() to post-handshake background task in TUI so first render is not blocked by server startup (CR #3) - Remove unused app_id/project_id from ImportSession and scanner (CR #4) - Add note on per-source-unit checkpoint granularity (CR #5) - Add fcntl file lock to prevent concurrent server spawn race (CR #6) - Fix loguru %s format to {} in state.py (CR #7) - Fix docstring step numbering (CR #8) - Remove redundant Table import in status_cmd (CR #9) Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
ecd02a9 to
5b2fe81
Compare
…er spawn lock fcntl is POSIX-only; importing it at module top crashes on Windows with ModuleNotFoundError. Use raven.utils.portable_lock.file_lock (portalocker- backed, POSIX fcntl + Windows LockFileEx) instead. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
EverOS server (everos/core/persistence/locking.py) imports fcntl which is POSIX-only. On native Windows: - onboard step 4: detect win32, warn user, skip memory config - backend.start(): detect win32, print Rich warning to stderr, degrade to NoOpAdapter instead of crashing Both paths guide users to WSL for full memory support. Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
## Summary Bump version from 0.1.7 to 0.1.8. Release commit only touches `pyproject.toml` and `uv.lock` (kept in sync via `uv lock`). Changes bundled into this release since v0.1.7: - feat(importer): cold-start import from other AI tools with EverOS HTTP backend (#170) - fix(build): pin locked dependency versions in installers (#185) - fix(cli): stop blank api key exiting deep_research prompt (#184) - fix: use redirect-free install.ps1 url on windows powershell 5.1 (#182) - fix(tui): brighten selection highlight for readability (#175) - fix(commitlint): align subject-case with conventional-commits standard (#187) ## Type - [x] Other ## Verification - [x] Relevant lint / type checks pass locally ``` python3 scripts/check_commit_messages.py origin/main..HEAD # exit 0 git diff --stat # pyproject.toml + uv.lock, 1 line each ``` ## Risk - [x] Backward compatibility considered Version bump only; no source changes. ## Related Issues N/A Co-authored-by: Claude (claude-opus-4-8) <noreply@anthropic.com>
Change description
Cold-start import: scan conversation history and memory files from other AI tools (starting with Claude Code), feed them into EverOS long-term memory so Raven knows the user from day one.
Key deliverables:
raven/importer/): Scanner protocol, ClaudeCodeScanner (JSONL conversations + memory/*.md files), orchestrator with batched store (100 msgs / 30K chars), idempotent state tracker with resume, cancel-flag stop mechanismraven import scan/run/status/stop): interactive platform/tier selection, Rich progress bar, background execution support, cancel viaraven import stopType of change
Related issues (if there is)
Checklists
Development
Security
Code review