ADR-0019: Import-path aliases as external action identifiers¶
- Status: proposed
- Date: 2026-04-13
- Deciders: @Aksem
- Tags: actions, api, architecture
Context¶
ADR-0006 establishes shared action-definition types as the identity contract for handler-to-handler invocation inside Python environments. That contract works because all participating environments share the same Python package and can reference the type directly.
External callers — the VS Code extension, MCP server, and CLI — cannot use Python types. They
communicate over JSON-RPC and must identify actions by a string. Currently these callers use a
project-local name (e.g. "lint"), which does not reflect the type-level contract and is
ambiguous across projects. The goal is to migrate to a string identity that corresponds to the
action-definition type.
Two string forms can represent an action-definition type:
- Import-path alias — the import path an extension author re-exports as their public API
(e.g.
finecode_extension_api.actions.LintAction). This is already the value users write in thesourcefield of project configuration. - Canonical path — the class's actual definition location, derived from
__module__and__qualname__. This path is globally unique without normalization but reflects internal module structure rather than the public API surface.
Related ADRs Considered¶
- ADR-0006 — establishes the type-level identity rule this ADR extends to the string domain.
- ADR-0007 — ensures at most one registration per action type per project, so alias normalization is unambiguous.
Decision¶
External callers identify actions by their import-path alias — the same string written in
the source field of project configuration. FineCode resolves aliases to the canonical path
internally; any valid import path that resolves to the registered action class is accepted.
This establishes the following rules:
- The action-definition class is the identity. Any import path that resolves to the same class as the registered action is a valid identifier. FineCode normalizes aliases to a canonical form for internal comparison.
- Canonical paths are an internal concern. Callers must not rely on paths derived from
__module__or__qualname__directly. These reflect internal module structure and may change when an extension reorganizes its codebase without altering its public API. - Users should prefer the highest-level import path the extension documents as its public
API. When multiple aliases resolve to the same class, the more general one (e.g.
finecode_extension_api.LintActionoverfinecode_extension_api.actions.LintAction) is less exposed to internal reorganization. The criterion is the extension author's documented stable surface, not shortest path.
Consequences¶
- Consistency with configuration. The same import-path string the user writes in
pyproject.tomlis the string they use in API calls. No new identifier form is introduced. - Stability under internal reorganization. When an extension author moves a class to a different internal module but preserves the public re-export, external callers are unaffected. Canonical paths do not provide this guarantee.
- Normalization is required. Because multiple aliases may refer to the same class, FineCode must normalize incoming identifiers before comparing. This is a resolution step that does not exist when canonical paths are used directly.
- Callers must use documented public aliases. An alias that resolves correctly today may stop resolving if the extension reorganizes its internals. Only aliases the extension author documents as stable should be used.
Alternatives Considered¶
Canonical paths only (__module__.__qualname__). Rejected because canonical paths expose
private module structure, diverge from what users write in configuration, and break whenever an
extension reorganizes its internal layout even when the public API is unchanged.