CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/nanoclaw-travel

Travel assistant for NanoClaw: byAir flight notifications (delay, gate, connection risk, inbound aircraft delay, time-to-leave, arrival logistics), traffic-aware drive planning for in-person meetings (auto drive blocks + leave-by traffic rechecks), travel-booking gap checks, and nightly TripIt sync. Per-chat overlay plugin.

Quality

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

High

Do not use without reviewing

Overview
Quality
Evals
Security
Files

home_address.pyskills/drive-engine/

"""Read the operator's canonical home address — the drive origin.

Every home-anchored drive leg (outbound from home, return to home) starts or
ends at the operator's current residence. That address has ONE canonical home
(Epic #59 §4): the machine-readable `## Addresses` block in the owner profile
`/workspace/trusted/user_profile.md`, owned by the `trusted-memory` skill in
the `nanoclaw-trusted` plugin. drive-engine is a READER of that block, never a
writer — the trusted plugin owns its shape and migration. (Epic #59 §4/§7 name
`nanoclaw-admin`; that is stale — the owning `trusted-memory` skill lives in
`nanoclaw-trusted` (whose `state-schema.md` names this reader), and this
reader itself lives in the `jbaruch/nanoclaw-travel` plugin.)

Read by `reconcile_sweep.py`, which resolves the home origin for every
home-anchored leg it plans.

The block the trusted plugin writes (Epic #59 §4):

    ## Addresses
    <!-- canonical, machine-read by travel tile -->
    - current_home: 12 Example St, Sampleton, TN 37000
    - home_airport: BNA
    - new_home_wip: 99 Placeholder Rd, Testburg, TN 37100

`current_home` is the drive origin. `new_home_wip` (a house under
construction) is deliberately NOT read — switching origins is a later,
explicit change, not an automatic pickup of whichever address appears first.

This is the deterministic reader (per `coding-policy: script-delegation` — a
fixed parse of a fixed block). It does NOT fall back to a guessed address: a
silent wrong origin would route every drive from the wrong place and quietly
mis-time every leave-by. A missing block raises with an actionable message
pointing at the trusted plugin.

stdlib-only per `coding-policy: dependency-management` (Stdlib First).

Public API:
    from home_address import read_current_home, HomeAddressError

    home = read_current_home()   # "12 Example St, Sampleton, TN 37000"
"""

from __future__ import annotations

import os
import re
from pathlib import Path

_DEFAULT_PROFILE_PATH = "/workspace/trusted/user_profile.md"
_PROFILE_PATH_ENV = "USER_PROFILE_PATH"

# The `## Addresses` section heading. `current_home` is read ONLY from inside
# this canonical block — a `current_home:` mention elsewhere in the profile
# (prose, an example, a stale note) must never set the drive origin.
_ADDRESSES_HEADING_RE = re.compile(r"^[ \t]*##[ \t]+Addresses[ \t]*$", re.MULTILINE)
# The next `## ` heading that closes the Addresses section.
_NEXT_H2_RE = re.compile(r"^[ \t]*##[ \t]+\S", re.MULTILINE)
# The canonical drive-origin key inside the `## Addresses` block. Matched as a
# `- current_home: <value>` list item, tolerant of surrounding whitespace.
_CURRENT_HOME_RE = re.compile(r"^\s*-\s*current_home\s*:\s*(?P<value>\S.*?)\s*$", re.MULTILINE)


def _addresses_section(text: str) -> str | None:
    """The body of the `## Addresses` block, or None when the heading is absent.

    Runs from just after the `## Addresses` heading to the next `## ` heading
    (or end of file). Scoping the `current_home` read to this block is what
    keeps a stale or example `current_home:` elsewhere in the profile from
    silently becoming the drive origin.
    """
    heading = _ADDRESSES_HEADING_RE.search(text)
    if heading is None:
        return None
    body = text[heading.end() :]
    nxt = _NEXT_H2_RE.search(body)
    return body[: nxt.start()] if nxt else body


class HomeAddressError(Exception):
    """Raised when the canonical home address cannot be read.

    The fix is always "make the trusted plugin's `## Addresses` block present and
    well-formed", not "retry" — the message says so. drive-engine refuses to
    guess an origin rather than route every drive from the wrong place.
    """


def profile_path() -> Path:
    """The owner-profile path; overridable via `USER_PROFILE_PATH` for tests."""
    return Path(os.environ.get(_PROFILE_PATH_ENV, _DEFAULT_PROFILE_PATH))


def read_current_home(*, path: Path | None = None) -> str:
    """Return the `current_home` address from the canonical Addresses block.

    Args:
        path: override the profile path (defaults to `profile_path()`).

    Returns:
        The `current_home` value, whitespace-trimmed.

    Raises:
        HomeAddressError: when the profile file is missing, carries no
            `## Addresses` block, or that block carries no non-empty
            `current_home:` entry — each with a message pointing at the
            `nanoclaw-trusted` trusted-memory Addresses block to fix. A
            `current_home:` outside the block is deliberately not read.
    """
    target = path if path is not None else profile_path()
    try:
        text = target.read_text(encoding="utf-8")
    except FileNotFoundError as exc:
        raise HomeAddressError(
            f"owner profile not found at {target} — the canonical home address lives in the "
            "`## Addresses` block of user_profile.md, owned by the nanoclaw-trusted trusted-memory "
            "skill; add the block (current_home: <address>) and redeploy"
        ) from exc
    except OSError as exc:
        raise HomeAddressError(f"owner profile at {target} is unreadable ({exc})") from exc

    section = _addresses_section(text)
    if section is None:
        raise HomeAddressError(
            f"no `## Addresses` block in {target} — the canonical home address lives in that "
            "block of user_profile.md (nanoclaw-trusted trusted-memory); add it with a "
            "`- current_home: <address>` line and redeploy"
        )
    match = _CURRENT_HOME_RE.search(section)
    if match is None:
        raise HomeAddressError(
            f"no `current_home:` entry in the `## Addresses` block of {target} — add "
            "`- current_home: <address>` to the canonical block (nanoclaw-trusted trusted-memory)"
        )
    return match["value"].strip()

README.md

tile.json