|
6 | 6 |
|
7 | 7 |  |
8 | 8 |  |
| 9 | +[](https://www.bestpractices.dev/projects/12294) |
9 | 10 |
|
10 | 11 | > **Build once, invoke by Code or AI.** |
11 | 12 |
|
@@ -40,7 +41,7 @@ A schema-enforced module standard for the AI-Perceivable era. |
40 | 41 | | `Registry` | Module storage -- discover, register, get, list, watch | |
41 | 42 | | `Executor` | Execution engine -- call with middleware pipeline, ACL, approval | |
42 | 43 | | `Context` | Request context -- trace ID, identity, call chain, cancel token | |
43 | | -| `Config` | Configuration -- load from YAML, get/set values | |
| 44 | +| `Config` | Configuration -- load from YAML, get/set values, namespace-partitioned Config Bus | |
44 | 45 | | `Identity` | Caller identity -- id, type, roles, attributes | |
45 | 46 | | `FunctionModule` | Wrapped function module created by `@module` decorator | |
46 | 47 |
|
@@ -99,6 +100,84 @@ A schema-enforced module standard for the AI-Perceivable era. |
99 | 100 | | `CancelToken` | Cooperative cancellation token | |
100 | 101 | | `BindingLoader` | Load modules from YAML binding files | |
101 | 102 | | `ErrorCodeRegistry` | Central registry for structured error codes | |
| 103 | +| `ErrorFormatterRegistry` | Surface-specific error formatter registry (MCP, A2A, CLI adapters) | |
| 104 | + |
| 105 | +## Configuration |
| 106 | + |
| 107 | +### Config Bus and Namespace Registration |
| 108 | + |
| 109 | +`Config` doubles as an ecosystem-level Config Bus. Any package can register a named namespace with optional JSON Schema validation, env prefix, and default values: |
| 110 | + |
| 111 | +```python |
| 112 | +from apcore import Config |
| 113 | + |
| 114 | +# Register a namespace (class-level, shared across all Config instances) |
| 115 | +Config.register_namespace( |
| 116 | + "my_plugin", |
| 117 | + schema={"type": "object", "properties": {"timeout_ms": {"type": "integer"}}}, |
| 118 | + env_prefix="MY_PLUGIN__", |
| 119 | + defaults={"timeout_ms": 5000}, |
| 120 | +) |
| 121 | + |
| 122 | +# Load config as usual |
| 123 | +config = Config.load("project.yaml") |
| 124 | + |
| 125 | +# Namespace-aware access |
| 126 | +timeout = config.get("my_plugin.timeout_ms") # dot-path with namespace resolution |
| 127 | +subtree = config.namespace("my_plugin") # full subtree as dict |
| 128 | + |
| 129 | +# Typed access |
| 130 | +config.get_typed("my_plugin.timeout_ms", int) |
| 131 | + |
| 132 | +# Mount an external source (no unified YAML required) |
| 133 | +config.mount("my_plugin", from_dict={"timeout_ms": 3000}) |
| 134 | + |
| 135 | +# Introspect registered namespaces |
| 136 | +names = Config.registered_namespaces() |
| 137 | +``` |
| 138 | + |
| 139 | +### Built-in Namespaces |
| 140 | + |
| 141 | +apcore pre-registers two namespaces that promote its existing flat config keys: |
| 142 | + |
| 143 | +| Namespace | Env prefix | Keys | |
| 144 | +|-----------|-----------|------| |
| 145 | +| `observability` | `APCORE__OBSERVABILITY` | tracing, metrics, logging, error_history, platform_notify | |
| 146 | +| `sys_modules` | `APCORE__SYS` | thresholds.error_rate, thresholds.latency_p99_ms | |
| 147 | + |
| 148 | +### Environment Variable Conventions |
| 149 | + |
| 150 | +| Pattern | When to use | Example | |
| 151 | +|---------|------------|---------| |
| 152 | +| `APCORE_KEY_NAME` | Override a flat top-level apcore key (existing convention) | `APCORE_EXECUTOR_DEFAULT__TIMEOUT=5000` | |
| 153 | +| `APCORE__NAMESPACE` prefix | Override keys inside a registered namespace (new convention) | `APCORE__OBSERVABILITY_TRACING_ENABLED=true` | |
| 154 | +| Custom prefix declared in `register_namespace` | Third-party packages with their own prefix | `MY_PLUGIN__TIMEOUT_MS=3000` | |
| 155 | + |
| 156 | +The double-underscore separator (`__`) in `APCORE__` avoids collisions with the existing single-underscore `APCORE_` flat-key prefix. Within each namespace, a single `_` maps to `.` and `__` maps to a literal `_`. |
| 157 | + |
| 158 | +### New Error Codes (0.15.0) |
| 159 | + |
| 160 | +| Code | Meaning | |
| 161 | +|------|---------| |
| 162 | +| `CONFIG_NAMESPACE_DUPLICATE` | A namespace with this name is already registered | |
| 163 | +| `CONFIG_NAMESPACE_RESERVED` | The namespace name is reserved (`_config`, `apcore`) | |
| 164 | +| `CONFIG_ENV_PREFIX_CONFLICT` | Two namespaces share the same env prefix | |
| 165 | +| `CONFIG_MOUNT_ERROR` | Failed to load or parse a mounted config source | |
| 166 | +| `CONFIG_BIND_ERROR` | Failed to deserialize a namespace subtree into the requested type | |
| 167 | +| `ERROR_FORMATTER_DUPLICATE` | A formatter for this surface is already registered | |
| 168 | + |
| 169 | +### Event Type Names |
| 170 | + |
| 171 | +Canonical event type names use dot-namespaced identifiers. `apcore.*` is reserved for core framework events; adapter packages use their own prefix (e.g., `apcore-mcp.*`). |
| 172 | + |
| 173 | +| Canonical name | Replaces | Emitted by | |
| 174 | +|---------------|---------|-----------| |
| 175 | +| `apcore.module.toggled` | `module_health_changed` | `system.control.toggle_feature` | |
| 176 | +| `apcore.health.recovered` | `module_health_changed` | `PlatformNotifyMiddleware` (error rate recovery) | |
| 177 | +| `apcore.config.updated` | `config_changed` | `system.control.update_config` | |
| 178 | +| `apcore.module.reloaded` | `config_changed` | `system.control.reload_module` | |
| 179 | + |
| 180 | +The legacy short-form names are still emitted alongside the canonical names during the transition period. |
102 | 181 |
|
103 | 182 | ## Documentation |
104 | 183 |
|
|
0 commit comments