Core
Config
chico.core.config
Configuration model and loader for chico.
Reads ~/.chico/config.yaml and produces typed configuration objects
that the plan engine uses to instantiate sources and providers.
Config file location: ~/.chico/config.yaml (created by chico init).
Example config
::
providers:
- name: kiro
type: kiro
level: global # "global" (~/.kiro) or "project" (.kiro/)
sources:
- name: kiro-configs
type: github
repo: org/kiro-config
path: configs/
branch: main # optional, default: main
token_env: GITHUB_TOKEN # optional, default: GITHUB_TOKEN
source_prefix: configs/ # optional, strip before mapping to kiro_dir
target: kiro # optional, which provider to sync into
policy:
strategy: safe # "safe" requires manual apply; "auto" applies immediately
Usage
::
from chico.core.config import load_config
config = load_config()
source_cfg = config.get_source("kiro-configs")
provider_cfg = config.get_provider("kiro")
Config
dataclass
The full parsed contents of ~/.chico/config.yaml.
Attributes:
| Name | Type | Description |
|---|---|---|
providers |
list[ProviderConfig]
|
List of configured providers. |
sources |
list[SourceConfig]
|
List of configured sources. |
policy |
PolicyConfig
|
Reconciliation policy settings. |
Source code in chico/core/config.py
filter_by_source(source_name)
Return a new Config containing only the named source.
Raises:
| Type | Description |
|---|---|
ConfigValidationError
|
If no source with the given name exists. |
Source code in chico/core/config.py
get_provider(name)
ConfigNotFoundError
Bases: Exception
Raised when ~/.chico/config.yaml does not exist.
Run chico init to create the default configuration file.
ConfigValidationError
PolicyConfig
dataclass
Reconciliation policy settings.
Attributes:
| Name | Type | Description |
|---|---|---|
strategy |
str
|
|
Source code in chico/core/config.py
ProviderConfig
dataclass
Configuration for a single provider.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique provider name. |
type |
str
|
Provider type. Currently only |
level |
str
|
Kiro directory scope. |
path |
str
|
Absolute path to the target directory. Only used when |
Source code in chico/core/config.py
SourceConfig
dataclass
Configuration for a single source.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique source name, referenced by |
type |
str
|
Source type. Currently only |
repo |
str
|
Full GitHub repository name in |
path |
str
|
Directory (or file) path inside the repository to fetch from. |
branch |
str
|
Branch to read from. Defaults to |
token_env |
str
|
Name of the environment variable holding the GitHub token.
Defaults to |
source_prefix |
str
|
Prefix to strip from source paths before mapping to the local
provider directory. For example, |
target |
str
|
Name of the provider this source syncs into. |
Source code in chico/core/config.py
load_config()
Load and validate ~/.chico/config.yaml.
Returns:
| Type | Description |
|---|---|
Config
|
The fully parsed configuration. |
Raises:
| Type | Description |
|---|---|
ConfigNotFoundError
|
If the config file does not exist. Run |
ConfigValidationError
|
If the config file is missing required fields. |
Source code in chico/core/config.py
Plan
chico.core.plan
Plan computation for chico.
A Plan is the computed changeset for a single chico plan run. It collects
all resource diffs across every source/provider pair declared in the
configuration, assigns a risk level, and provides a stable identifier for
auditing.
Example usage::
from chico.core.config import load_config
from chico.core.plan import compute_plan
config = load_config()
plan = compute_plan(config)
if plan.has_changes:
for diff in plan.changes:
print(diff.change_type, diff.resource_id)
Plan
dataclass
A computed changeset produced by chico plan.
Attributes:
| Name | Type | Description |
|---|---|---|
plan_id |
str
|
Unique identifier for this plan run (UUID4). |
changes |
list[Diff]
|
All resource diffs that require an action. Diffs with
|
risk_level |
RiskLevel
|
Estimated risk of applying this plan. |
Source code in chico/core/plan.py
has_changes
property
Return True if there is at least one actionable change.
RiskLevel
Bases: StrEnum
Estimated risk of applying a plan.
Values
NONE: No changes — nothing would be modified. LOW: Only new resources would be created; nothing would be overwritten. MEDIUM: Existing resources would be modified. HIGH: Resources would be deleted.
Source code in chico/core/plan.py
compute_plan(config)
Compute a plan from the given configuration.
For every source declared in config, fetches the desired state and
computes a diff against the current local state. Aggregates all diffs
into a single :class:Plan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The loaded chico configuration. |
required |
Returns:
| Type | Description |
|---|---|
Plan
|
The computed changeset. :attr: |
Raises:
| Type | Description |
|---|---|
SourceFetchError
|
If any source fails to fetch the desired state. |
ValueError
|
If a source or provider type declared in the config is not supported. |
Source code in chico/core/plan.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
Apply
chico.core.apply
Apply engine for chico.
Fetches desired state from every configured source, diffs it against local
state, applies all changes, and persists the result to ~/.chico/state.json.
Example usage::
from chico.core.config import load_config
from chico.core.apply import execute_apply
config = load_config()
result = execute_apply(config)
print(f"Applied {result.ok_count}, {result.error_count} error(s).")
ApplyResult
dataclass
The outcome of execute_apply.
Attributes:
| Name | Type | Description |
|---|---|---|
plan |
Plan
|
The computed changeset that was applied. |
results |
list[Result]
|
One :class: |
Source code in chico/core/apply.py
error_count
property
Number of resources that failed to apply.
has_errors
property
Return True if at least one resource failed to apply.
ok_count
property
Number of resources applied successfully.
execute_apply(config)
Fetch desired state, apply all changes, and persist state.
For every source declared in config, fetches the desired state,
computes a diff, and calls :meth:~chico.core.resource.Resource.apply
on every resource that has changes. Updates ~/.chico/state.json
with the versions and results afterwards.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The loaded chico configuration. |
required |
Returns:
| Type | Description |
|---|---|
ApplyResult
|
The plan that was executed and the per-resource results. |
Raises:
| Type | Description |
|---|---|
SourceFetchError
|
If any source fails to fetch the desired state. |
ValueError
|
If a source or provider type declared in the config is not supported. |
Source code in chico/core/apply.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
State
chico.core.state
State management for chico.
The state file (~/.chico/state.json) is the source of truth for what
chico last applied. It tracks the commit hash (or equivalent version) of
every source that has been synced, enabling drift detection on subsequent
runs.
Example usage::
from chico.core.state import State, load_state, save_state
state = load_state()
# After a successful apply from a GitHub source:
state.record_version("kiro-configs", "abc123def456")
save_state(state)
# On the next run, check if the source has moved ahead:
last_hash = state.get_version("kiro-configs") # "abc123def456"
State
dataclass
Represents the persisted state of chico.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
str
|
High-level status of the last operation ( |
last_run |
dict | None
|
Metadata about the most recent run (result, change count, etc.).
|
resources |
list[dict]
|
List of resource snapshots recorded during the last apply. |
versions |
dict[str, str]
|
Mapping of source name → version string (e.g. commit SHA) of the last successfully applied snapshot for that source. |
Source code in chico/core/state.py
get_version(source_name)
Return the last applied version for a source, or None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_name
|
str
|
The name of the source to look up. |
required |
record_version(source_name, version)
Record the version of a source that was just applied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_name
|
str
|
The name of the source as declared in |
required |
version
|
str
|
The version identifier (e.g. full Git commit SHA) of the snapshot that was applied. |
required |
Source code in chico/core/state.py
load_state()
Load state from ~/.chico/state.json.
Returns a default :class:State if the file does not exist yet
(e.g. right after chico init).
Source code in chico/core/state.py
save_state(state)
Persist a :class:State to ~/.chico/state.json.
Creates the parent directory if it does not exist.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State
|
The state to write. |
required |
Source code in chico/core/state.py
Resource
chico.core.resource
Core resource abstractions for chico.
This module defines the fundamental building blocks of chico's reconciliation
model. Every system that chico manages is represented as a :class:Resource.
Changes between desired and current state are described as a :class:Diff,
and the outcome of applying a change is captured in a :class:Result.
Example usage::
from chico.core.resource import Resource, Diff, Result, ChangeType, ResultStatus
class MyResource:
@property
def resource_id(self) -> str:
return "my-resource"
def desired_state(self) -> dict:
return {"enabled": True}
def current_state(self) -> dict:
return {"enabled": False}
def diff(self) -> Diff:
return Diff(
change_type=ChangeType.MODIFY,
resource_id=self.resource_id,
changes={"enabled": FieldChange(from_value=False, to_value=True)},
)
def apply(self) -> Result:
# ... apply logic ...
return Result(status=ResultStatus.OK, resource_id=self.resource_id)
ChangeType
Bases: StrEnum
Describes the nature of a change to a resource.
Values
ADD: The resource does not exist in the current state and will be created. MODIFY: The resource exists but one or more fields differ from the desired state. REMOVE: The resource exists in the current state but is absent from the desired state. NONE: The resource is fully in sync — no action required.
Source code in chico/core/resource.py
Diff
dataclass
Describes all changes required to bring a resource to its desired state.
A Diff is the output of :meth:Resource.diff. It tells the plan engine
what would change and how, without actually applying anything.
Attributes:
| Name | Type | Description |
|---|---|---|
change_type |
ChangeType
|
The high-level category of change (add, modify, remove, or none). |
resource_id |
str
|
The unique identifier of the resource this diff belongs to. |
changes |
dict[str, FieldChange]
|
A mapping of field names to their :class: |
Properties
has_changes:
True when there is at least one actionable change.
Source code in chico/core/resource.py
has_changes
property
Return True if this diff represents an actionable change.
FieldChange
dataclass
Captures a before/after value for a single field within a :class:Diff.
Attributes:
| Name | Type | Description |
|---|---|---|
from_value |
Any
|
The field's value in the current (live) state. |
to_value |
Any
|
The field's value in the desired state. |
Source code in chico/core/resource.py
Resource
Bases: Protocol
Protocol that every chico-managed resource must satisfy.
A resource is the fundamental unit of chico's reconciliation model. It knows its own desired state (what it should look like) and current state (what it actually looks like), can compute the diff between the two, and can apply that diff.
Implementors do not need to inherit from this class — any object that
exposes the attributes and methods below is a valid Resource.
Example
Implement the protocol on any plain class::
class ConfigFileResource:
def __init__(self, path: Path, desired: dict) -> None:
self._path = path
self._desired = desired
@property
def resource_id(self) -> str:
return str(self._path)
def desired_state(self) -> dict:
return self._desired
def current_state(self) -> dict:
if self._path.exists():
return yaml.safe_load(self._path.read_text())
return {}
def diff(self) -> Diff:
...
def apply(self) -> Result:
...
Source code in chico/core/resource.py
resource_id
property
Unique, stable identifier for this resource within its provider.
apply()
Apply the changes described by :meth:diff to the live system.
This method must be idempotent: calling it when the resource is
already in sync must return :attr:ResultStatus.OK without side
effects.
Source code in chico/core/resource.py
current_state()
desired_state()
diff()
Compute the diff between desired and current state.
Returns a :class:Diff with change_type=ChangeType.NONE when
the resource is already in sync.
Result
dataclass
The outcome of calling :meth:Resource.apply.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
ResultStatus
|
Whether the apply succeeded, failed, or was skipped. |
resource_id |
str
|
The unique identifier of the resource that was acted on. |
message |
str
|
Optional human-readable detail, especially useful on error. |
Source code in chico/core/resource.py
ok
property
Return True when the result status is :attr:ResultStatus.OK.
ResultStatus
Bases: StrEnum
Outcome of applying a resource change.
Values
OK:
The change was applied successfully.
ERROR:
The change failed. Inspect :attr:Result.message for details.
SKIPPED:
The change was intentionally not applied (e.g. dry-run mode).
Source code in chico/core/resource.py
Provider
chico.core.provider
Provider protocol for chico.
A provider encapsulates a target system — such as a filesystem directory,
Kiro, or any future integration — and exposes the resources that system
contains as a flat list of :class:~chico.core.resource.Resource objects.
The plan engine calls :meth:Provider.list_resources to discover what
currently exists in a system before computing diffs.
Example usage::
from chico.core.provider import Provider
from chico.core.resource import Resource
class FilesystemProvider:
def __init__(self, root: Path) -> None:
self._root = root
@property
def name(self) -> str:
return f"filesystem:{self._root}"
def list_resources(self) -> list[Resource]:
return [
ConfigFileResource(path)
for path in self._root.glob("**/*.yaml")
]
Provider
Bases: Protocol
Protocol that every chico provider must satisfy.
A provider is responsible for a single target system. It knows how to
enumerate all :class:~chico.core.resource.Resource objects that belong
to that system, which the plan engine uses to compute the full changeset.
Implementors do not need to inherit from this class — any object that
exposes the attributes and methods below is a valid Provider.
Example
::
class KiroProvider:
@property
def name(self) -> str:
return "kiro"
def list_resources(self) -> list[Resource]:
return [KiroPromptResource(p) for p in kiro.list_prompts()]
Source code in chico/core/provider.py
name
property
Unique name identifying this provider (e.g. "filesystem", "kiro").
list_resources()
Return all resources managed by this provider.
The returned list reflects the current state of the system. Each resource is responsible for computing its own desired state and diff when requested by the plan engine.
Source code in chico/core/provider.py
Source
chico.core.source
Source protocol and FetchResult for chico.
A source is where desired state comes from — a GitHub repository, an S3 bucket, or any future backend. Sources are read-only: they fetch files and return the version (commit hash, ETag, etc.) that was retrieved.
The fetched version is recorded in ~/.chico/state.json after a successful
apply so that drift can be detected on the next run.
Example usage::
from chico.core.source import Source, FetchResult
class MySource:
@property
def name(self) -> str:
return "my-source"
def fetch(self) -> FetchResult:
return FetchResult(
version="abc123def456",
files={"steering.md": "# Steering file content"},
)
FetchResult
dataclass
The result of fetching desired state from a source.
Attributes:
| Name | Type | Description |
|---|---|---|
version |
str
|
An opaque string that uniquely identifies the fetched snapshot. For GitHub sources this is the full commit SHA. For S3 it would be an ETag or object version ID. Stored in state after apply to enable drift detection. |
files |
dict[str, str]
|
A mapping of relative file paths to their text content, as fetched from the source. |
Source code in chico/core/source.py
Source
Bases: Protocol
Protocol that every chico source must satisfy.
A source knows how to fetch the desired state for a set of files from an external system and return the version identifier of what was fetched.
Implementors do not need to inherit from this class — any object that
exposes the attributes and methods below is a valid Source.
Example
::
class GitHubSource:
@property
def name(self) -> str:
return "kiro-configs"
def fetch(self) -> FetchResult:
# ... fetch files from GitHub ...
return FetchResult(version=commit_sha, files=files)
Source code in chico/core/source.py
name
property
Unique name identifying this source, matching the config entry.
fetch()
Fetch the current desired state from the source.
Returns a :class:FetchResult containing all files and the version
identifier of the snapshot that was retrieved.
Raises:
| Type | Description |
|---|---|
SourceFetchError
|
If the source cannot be reached or authentication fails. |
Source code in chico/core/source.py
SourceFetchError
Bases: Exception
Raised when a source fails to fetch desired state.
Wraps the underlying exception so callers can handle fetch failures without depending on source-specific exception types.