Rename Installation to Instance

Follows the portal: the noun is "instance" everywhere the app says it —
UI strings, CLI output, error details, docs and comments. The wire keys
(`instance_id`, `instance_token`) and the hub route this calls move with it.

An existing cloud.json is adopted rather than refused: without the key
alias the dataclass fails to parse, which the caller swallows and reads as
"never enrolled" instead of "reconnect".

`instance_key` on a node type becomes `target_key`. It means the outside
thing a node points at, which is a different sense of the word, and keeping
both would put two meanings of "instance" in one codebase.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
2026-08-31 10:12:01 +02:00
co-authored by Claude Opus 5
parent 6534855492
commit d01a8dad37
101 changed files with 374 additions and 375 deletions
+2 -2
View File
@@ -682,7 +682,7 @@ def _flow_state(flow: dict[str, Any]) -> str:
def _portal_phrase(portal: dict[str, Any]) -> tuple[str, str]:
"""Where this installation stands with its portal, and how to colour it.
"""Where this instance stands with its portal, and how to colour it.
Three states worth telling apart: never paired, paired and linked, and
paired but not reaching it — the last being the one somebody needs to know
@@ -734,7 +734,7 @@ def _status_screen(client: Client) -> Any:
summary = client.summary()
flows = client.flows()
# Both, because an installation is usually one or the other: a live flow
# Both, because an instance is usually one or the other: a live flow
# fails as an engine event, while a batch run fails on its own row.
failures = client.events(kind="failure", limit=5)
runs = client.runs(limit=5)
+10 -10
View File
@@ -57,7 +57,7 @@ RETRY_STATUS = frozenset({502, 503, 504})
WAIT_TOLERANCE = 5
#: What a project-local installation is called, beside `.venv` and `.git`.
#: What a project-local instance is called, beside `.venv` and `.git`.
DATA_DIR_NAME = ".fluksio"
#: The shared one, for a machine that wants a single engine rather than one
@@ -66,10 +66,10 @@ GLOBAL_DATA_DIR = Path("~/.fluksio")
def find_data_dir(start: Path | None = None) -> Path | None:
"""The nearest project-local installation, walking up from ``start``.
"""The nearest project-local instance, walking up from ``start``.
The same search `.git` and `.venv` get, and for the same reason: which
installation you mean is a fact about where you are standing, not about
instance you mean is a fact about where you are standing, not about
which machine you are on. Several repositories on one device each keep
their own flows, runs and token this way rather than sharing one.
"""
@@ -82,16 +82,16 @@ def find_data_dir(start: Path | None = None) -> Path | None:
def data_dir(start: Path | None = None) -> Path:
"""The installation this working directory belongs to."""
"""The instance this working directory belongs to."""
found = find_data_dir(start)
return found if found is not None else GLOBAL_DATA_DIR.expanduser()
def config_path(directory: Path | None = None) -> Path:
"""Where the token for an installation lives — beside the data it opens.
"""Where the token for an instance lives — beside the data it opens.
Not a single file per machine: a token is for one engine, and with an
installation per repository there is more than one. Keeping it inside the
instance per repository there is more than one. Keeping it inside the
data directory means the client finds the credential for the engine whose
directory it is standing in, without either having to be told.
"""
@@ -99,7 +99,7 @@ def config_path(directory: Path | None = None) -> Path:
def _legacy_config_path() -> Path:
"""Where `fluksio login` used to write, before installations were local."""
"""Where `fluksio login` used to write, before instances were local."""
base = os.environ.get("XDG_CONFIG_HOME") or str(Path.home() / ".config")
return Path(base) / "fluksio" / "client.json"
@@ -290,7 +290,7 @@ class Client:
return result
def cloud_status(self) -> dict[str, Any]:
"""Whether this installation is enrolled with a portal, and linked."""
"""Whether this instance is enrolled with a portal, and linked."""
result: dict[str, Any] = self._call("GET", "/cloud/status")
return result
@@ -585,7 +585,7 @@ class RunHandle:
def ignore_self(directory: Path) -> None:
"""Keep an installation out of the repository it sits in.
"""Keep an instance out of the repository it sits in.
It holds a token and a database, neither of which belongs in anybody's
history. A `.gitignore` of `*` inside the directory ignores it from within,
@@ -595,7 +595,7 @@ def ignore_self(directory: Path) -> None:
marker = directory / ".gitignore"
if not marker.exists():
directory.mkdir(parents=True, exist_ok=True)
marker.write_text("# A Fluksio installation: a database, and a token.\n*\n")
marker.write_text("# A Fluksio instance: a database, and a token.\n*\n")
def write_config(url: str, token: str, directory: Path | None = None) -> Path: