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
+14 -17
View File
@@ -28,7 +28,7 @@ from typing import Any
import fluksio
#: Where an installation keeps everything, unless it is told otherwise.
#: Where an instance keeps everything, unless it is told otherwise.
DEFAULT_HOME = Path("~/.fluksio")
#: The portal a claim code is redeemed at, unless another is named. Having a
@@ -52,7 +52,7 @@ def _say(message: str = "") -> None:
def _data_dir(raw: str | None, shared: bool = False) -> Path:
"""Which installation this command is for.
"""Which instance this command is for.
A repository with its own venv wants its own engine too — its own flows,
its own run history, its own token — so the default is a `.fluksio` beside
@@ -73,12 +73,12 @@ def _data_dir(raw: str | None, shared: bool = False) -> Path:
return path.resolve()
def _mention_other_installation(data_dir: Path) -> None:
def _mention_other_instance(data_dir: Path) -> None:
"""Say when there is a second engine, so neither goes looking lost."""
shared = DEFAULT_HOME.expanduser().resolve()
if data_dir == shared or not (shared / "fluksio.db").exists():
return
_say(f" Note {shared} holds another installation; this one is separate.")
_say(f" Note {shared} holds another instance; this one is separate.")
_say(" `fluksio serve --global` runs that one instead.")
@@ -217,8 +217,7 @@ def _enroll(portal: str, code: str, as_email: str | None) -> int:
return 1
_say(
f"Connected to {config.portal_url} as {email} "
f"(installation {config.installation_id})."
f"Connected to {config.portal_url} as {email} (instance {config.instance_id})."
)
return 0
@@ -340,7 +339,7 @@ def probe_engine(url: str, token: str, client: Any = None) -> str:
makes stopping it something this command may offer. The proof is the
token: it is signed with this directory's secret key, so an engine that
accepts it is one reading this directory's database. A Fluksio belonging
to another installation answers the health check and refuses the token,
to another instance answers the health check and refuses the token,
and is only ever named — never stopped from here.
"""
import logging
@@ -443,7 +442,7 @@ def cmd_serve(args: argparse.Namespace) -> int:
if port != DEFAULT_PORT:
# Moving off the port quietly makes starting a second engine for
# one directory look like it worked. Two of them on one SQLite
# file is not a supported shape — two *installations* on one
# file is not a supported shape — two *instances* on one
# machine is — so the one already up is named instead.
url = f"http://{reachable}:{DEFAULT_PORT}"
who = probe_engine(url, _token_for(data_dir))
@@ -455,7 +454,7 @@ def cmd_serve(args: argparse.Namespace) -> int:
return 0
if who == "foreign":
_say(
f"Port {DEFAULT_PORT} holds another installation's Fluksio; "
f"Port {DEFAULT_PORT} holds another instance's Fluksio; "
f"serving on {port} instead."
)
else:
@@ -480,15 +479,15 @@ def cmd_serve(args: argparse.Namespace) -> int:
_say(f" Nodes {modules.venv_dir() / 'bin' / 'python'}")
_say(" a venv of its own; the Modules screen installs into it.")
if config is not None:
_say(f" Portal {config.portal_url}, installation {config.installation_id}")
_say(f" Portal {config.portal_url}, instance {config.instance_id}")
_say(" The dashboard is served by the portal; nothing is served here.")
else:
_say(" No portal. Pair this installation with:")
_say(" No portal. Pair this instance with:")
_say(" fluksio enroll <code>")
_say(f" Signed in as {admin_email}")
_say(f" token in {token_path}")
_mention_undeclared_cards()
_mention_other_installation(data_dir)
_mention_other_instance(data_dir)
# One process: it holds the flow engine, and a second worker would be a
# second engine — duplicated subscriptions, cron ticks and webhooks.
@@ -558,13 +557,13 @@ def _parser() -> argparse.ArgumentParser:
sub.add_argument(
"--data-dir",
default=os.environ.get("FLUKSIO_HOME"),
help="where this installation keeps everything (default: ./.fluksio)",
help="where this instance keeps everything (default: ./.fluksio)",
)
sub.add_argument(
"--global",
dest="shared",
action="store_true",
help=f"use the shared installation at {DEFAULT_HOME} instead",
help=f"use the shared instance at {DEFAULT_HOME} instead",
)
serve = subparsers.add_parser("serve", help="run the engine")
@@ -622,9 +621,7 @@ def _parser() -> argparse.ArgumentParser:
)
serve.set_defaults(func=cmd_serve)
enroll = subparsers.add_parser(
"enroll", help="pair this installation with a portal"
)
enroll = subparsers.add_parser("enroll", help="pair this instance with a portal")
enroll.add_argument("code", help="the claim code minted on the portal")
enroll.add_argument(
"--portal",