Skip to content

Add JSON-file local-mode transport (alternative to WebSocket) #38

Description

@AndresL230

Severity: Medium
Affected repos: middleware-python
Component boundary: middleware (local mode) → on-disk file

Motivation

_LocalTransport in recost/_transport.py defaults to local mode when api_key is missing and opens ws://127.0.0.1:9847. The VS Code extension does not host that server and has decided not to — see recost-dev/extension#91. Every default-configured SDK in local mode reconnects forever to nothing.

A file-based transport gives users a working "no cloud account" path without a localhost listener: the SDK writes WindowSummary frames to disk; tooling can read them later.

Proposal

Add a local-file transport mode alongside the existing WS mode.

  • Config: RecostConfig.local_transport: Literal["ws", "file"]. Default: "file". The WS target does not exist (recost-dev/extension#91), so the new default writes telemetry to disk instead of silently dropping it. "ws" remains as an opt-in. Behavior change for anyone currently using local mode by accident, but their telemetry was going nowhere — so this is strictly an improvement.
  • Wire format: append-only NDJSON. Each line is exactly one json.dumps(window_summary.to_dict()). Every frame carries a top-level protocol_version: "1.0" (covers recost-dev/extension#99 for this transport).
  • Location: os.environ.get("RECOST_LOCAL_DIR") or pathlib.Path.home() / ".recost" / "local-telemetry" then f"{project_id}.jsonl".
  • Permissions: 0o600 on POSIX; document the Windows ACL limitation.
  • Failure modes: disk-full / PermissionError drops the oldest queued frame, fires on_error once per overflow episode. Never raises.
  • Lifecycle: flush + close stream on dispose().

Open for the implementer

  • Rotation (per-day? per-size? both?) and retention.
  • Multi-process concurrency on the same project_id (POSIX O_APPEND atomicity vs Windows).
  • Whether the existing WS transport is eventually removed (separate issue).

Verification

  • init(project_id="proj_x") (no local_transport set → uses new default "file") + 3 requests.get() calls writes 3 NDJSON lines with protocol_version: "1.0".
  • init(project_id="proj_x", local_transport="ws") still attempts the existing WS path.
  • dispose() flushes within 1s.
  • File mode 0o600 on POSIX.

Out of scope

  • Reading the files (no consumer exists — extension explicitly opted out per recost-dev/extension#91).
  • Removing the existing WebSocket transport.
  • Encryption / signing of on-disk frames.

Related

  • recost-dev/extension#91, recost-dev/extension#99
  • Node mirror: cross-referenced in a follow-up comment.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Should fix before next releaseenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions