Skip to content

Commit c3bc951

Browse files
committed
docs: Generalize type mapping and schema definitions by removing specific library implementations and code examples.
1 parent ab941c3 commit c3bc951

File tree

6 files changed

+156
-775
lines changed

6 files changed

+156
-775
lines changed

PROTOCOL_SPEC.md

Lines changed: 61 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,10 @@ relying on language-native namespace mechanisms to avoid conflicts:
130130
| Rust | Module path | `apcore::Module` |
131131
| TypeScript | Module import | `import { Module } from 'apcore'` |
132132
| Java | Package path | `import com.apcore.Module` |
133-
| C | Name prefix | `apcore_module_t`, `apcore_module(...)` |
134133

135134
Implementations **MUST** follow these naming rules:
136135
- In languages with namespace mechanisms, **MUST NOT** add redundant prefixes to public APIs
137-
- In languages without namespace mechanisms (e.g., C), **MUST** use `apcore_` prefix
136+
- In languages without namespace mechanisms, **MUST** use `apcore_` prefix
138137
- Error types **SHOULD** be prefixed with their domain (e.g., `ModuleError`, `SchemaValidationError`)
139138

140139
---
@@ -1203,7 +1202,7 @@ schema:
12031202
strategy: "yaml_first" # yaml_first | native_first | yaml_only
12041203
12051204
# yaml_first: Load from YAML first, native implementation can override
1206-
# native_first: Prefer native implementation (Pydantic/struct), YAML as fallback
1205+
# native_first: Prefer native implementation, YAML as fallback
12071206
# yaml_only: Only use YAML (pure cross-language scenario)
12081207
12091208
paths:
@@ -1217,13 +1216,7 @@ schema:
12171216

12181217
### 4.10 Language-specific Schema Implementations
12191218

1220-
| Language | Native Implementation | YAML Loading Support |
1221-
|------|----------|--------------|
1222-
| Python | Pydantic v2 | YAML → Pydantic dynamic generation |
1223-
| Rust | serde + validator | YAML → JSONSchema runtime validation |
1224-
| Go | struct + go-playground/validator | YAML → JSONSchema runtime validation |
1225-
| Java | Jackson + Bean Validation | YAML → POJO code generation |
1226-
| TypeScript | Zod / TypeBox | YAML → Zod schema generation |
1219+
Each language SDK **must** provide a native schema implementation that supports JSON Schema Draft 2020-12 validation and YAML schema loading. The specific library choices are left to SDK implementers.
12271220

12281221
### 4.11 Schema References ($ref)
12291222

@@ -4453,21 +4446,20 @@ When bridging `Executor.stream()` to MCP, implementations SHOULD use the standar
44534446

44544447
### 12.3 Cross-language Implementation Requirements
44554448

4456-
| Requirement | Python | Rust | Go | Java | TypeScript |
4457-
|------|--------|------|----|------|------------|
4458-
| Schema validation library | Pydantic v2 | serde + validator | struct + validator | Jackson + Bean Validation | Zod / Ajv |
4459-
| Async model | asyncio | tokio | goroutine | CompletableFuture / Virtual Threads | async/await (Promise) |
4460-
| Package management | pyproject.toml + uv/pip | Cargo.toml | go.mod | Maven / Gradle | package.json |
4461-
| JSON Schema support | MUST | MUST | MUST | MUST | MUST |
4462-
| YAML parsing | MUST | MUST | MUST | MUST | MUST |
4463-
| Directory as ID | MUST | MUST | MUST | MUST | MUST |
4464-
| ID Map cross-language conversion | MUST | MUST | MUST | MUST | MUST |
4465-
| ACL engine | MUST | MUST | MUST | MUST | MUST |
4466-
| Middleware onion model | MUST | MUST | MUST | MUST | MUST |
4467-
| OpenTelemetry integration | SHOULD | SHOULD | SHOULD | SHOULD | SHOULD |
4468-
| Structured logging | MUST | MUST | MUST | MUST | MUST |
4469-
| Error code specification | MUST | MUST | MUST | MUST | MUST |
4470-
| Executor.validate() preflight | SHOULD | SHOULD | SHOULD | SHOULD | SHOULD |
4449+
All SDK implementations **must** satisfy the following requirements regardless of language:
4450+
4451+
| Requirement | Level |
4452+
|------|--------|
4453+
| JSON Schema Draft 2020-12 validation | MUST |
4454+
| YAML parsing | MUST |
4455+
| Directory as ID | MUST |
4456+
| ID Map cross-language conversion | MUST |
4457+
| ACL engine | MUST |
4458+
| Middleware onion model | MUST |
4459+
| Structured logging | MUST |
4460+
| Error code specification | MUST |
4461+
| OpenTelemetry integration | SHOULD |
4462+
| Executor.validate() preflight | SHOULD |
44714463

44724464
### 12.4 Consistency Testing Requirements
44734465

@@ -4551,35 +4543,7 @@ Phase 4: Advanced
45514543

45524544
### 12.6 Language-specific Guidelines
45534545

4554-
#### Python
4555-
- Schema: Pydantic v2
4556-
- Async: asyncio
4557-
- Package management: pyproject.toml + uv/pip
4558-
4559-
#### TypeScript
4560-
- Schema: @sinclair/typebox
4561-
- Async: async/await (Promise)
4562-
- Package management: package.json
4563-
4564-
#### Rust
4565-
- Schema: serde + validator
4566-
- Async: tokio
4567-
- Package management: Cargo.toml
4568-
4569-
#### Go
4570-
- Schema: struct + validator
4571-
- Async: goroutine
4572-
- Package management: go.mod
4573-
4574-
#### Java
4575-
- Schema: Jackson + Bean Validation
4576-
- Async: CompletableFuture / Virtual Threads
4577-
- Package management: Maven / Gradle
4578-
4579-
#### C / C++
4580-
- Schema: cJSON (C) / nlohmann-json + valijson (C++)
4581-
- Async: pthreads / std::async / libuv
4582-
- Package management: CMake / vcpkg / Conan
4546+
Each SDK implementation **should** use the idiomatic schema validation, async model, and package management conventions of its target language. Specific library choices are documented in each SDK's own repository.
45834547

45844548
### 12.7 Concurrency Model Specification
45854549

@@ -4851,70 +4815,56 @@ SDK implementers.
48514815

48524816
#### 12.8.2 Error Handling Mapping
48534817

4854-
The Python/TypeScript/Java implementations use try/catch to convert exceptions into check results.
4855-
Languages with error-return semantics (Go, Rust, C) naturally map to this pattern:
4818+
Each check in validate() calls the same helper functions used by the `call()` pipeline. Failures are appended to the `checks` list rather than thrown/returned immediately.
48564819

4857-
| Language Family | Pipeline helper style | validate() adaptation |
4858-
|----------------|----------------------|----------------------|
4859-
| **Python / TypeScript / Java** | Throws exceptions | `try { helper(); push(passed) } catch(e) { push(failed, e) }` |
4860-
| **Go** | Returns `error` | `if err := helper(); err != nil { push(failed, err) } else { push(passed) }` |
4861-
| **Rust** | Returns `Result<T, E>` | `match helper() { Ok(_) => push(passed), Err(e) => push(failed, e) }` |
4862-
| **C / C++** | Returns error code / status | `status = helper(); if (status != OK) { push(failed, status) } else { push(passed) }` |
4820+
| Error Model | Pattern |
4821+
|-------------|---------|
4822+
| **Exception-based** (try/catch) | `try { helper(); push(passed) } catch(e) { push(failed, e) }` |
4823+
| **Error-return** (Go, Rust) | `if err := helper(); err != nil { push(failed, err) } else { push(passed) }` |
48634824

4864-
> **Note:** Go and Rust error-return patterns are more natural than try/catch for this "collect all errors" flow.
4825+
> **Note:** Error-return patterns are more natural than try/catch for this "collect all errors" flow.
48654826
4866-
#### 12.8.3 PreflightResult Type Mapping
4827+
#### 12.8.3 PreflightResult Type
48674828

4868-
```
4869-
Python: @dataclass PreflightResult + @property errors
4870-
TypeScript: interface PreflightResult + readonly errors (computed in factory)
4871-
Go: type PreflightResult struct + func (r *PreflightResult) Errors() []map[string]any
4872-
Rust: pub struct PreflightResult + impl PreflightResult { pub fn errors(&self) -> Vec<...> }
4873-
Java: public record PreflightResult(...) + public List<Map<String, Object>> errors()
4874-
C: typedef struct preflight_result_t + preflight_result_errors(result, out, size)
4875-
C++: struct PreflightResult + std::vector<Error> errors() const
4876-
```
4829+
`PreflightResult` **must** contain the following fields:
48774830

4878-
#### 12.8.4 PreflightCheckResult Type Mapping
4831+
| Field | Type | Description |
4832+
|-------|------|-------------|
4833+
| `valid` | boolean | `true` if all checks passed |
4834+
| `checks` | list of `PreflightCheckResult` | Ordered list of check results |
4835+
| `requires_approval` | boolean | Whether the module requires approval |
4836+
| `errors` (computed) | list of error objects | Filtered view: only checks where `passed` is `false` |
48794837

4880-
```
4881-
Python: @dataclass(frozen=True) PreflightCheckResult { check: str, passed: bool, error: dict | None }
4882-
TypeScript: interface PreflightCheckResult { readonly check: string; readonly passed: boolean; readonly error?: Record<string, unknown> }
4883-
Go: type PreflightCheckResult struct { Check string; Passed bool; Error map[string]any }
4884-
Rust: pub struct PreflightCheckResult { pub check: String, pub passed: bool, pub error: Option<HashMap<String, Value>> }
4885-
Java: public record PreflightCheckResult(String check, boolean passed, Map<String, Object> error)
4886-
C: typedef struct { const char* check; bool passed; cJSON* error; } preflight_check_result_t;
4887-
C++: struct PreflightCheckResult { std::string check; bool passed; std::optional<json> error; };
4888-
```
4838+
#### 12.8.4 PreflightCheckResult Type
4839+
4840+
`PreflightCheckResult` **must** contain the following fields:
4841+
4842+
| Field | Type | Description |
4843+
|-------|------|-------------|
4844+
| `check` | string | Check name (e.g., `"module_id_format"`, `"acl"`, `"schema"`) |
4845+
| `passed` | boolean | Whether the check passed |
4846+
| `error` | error object or null | Error details when `passed` is `false` |
48894847

4890-
#### 12.8.5 Schema Validation Library Requirements
4848+
#### 12.8.5 Schema Validation
48914849

48924850
validate() Check 6 (schema) reuses the same JSON Schema validation that `call()` Step 6 already performs.
4893-
No additional schema library is required beyond what the SDK already uses:
4894-
4895-
| Language | Recommended Library | Notes |
4896-
|----------|-------------------|-------|
4897-
| Python | Pydantic v2 | `model_validate()` for check, `ValidationError` for details |
4898-
| TypeScript | @sinclair/typebox | `Value.Check()` + `Value.Errors()` |
4899-
| Go | `santhosh-tekuri/jsonschema` or `xeipuuv/gojsonschema` | Mature, JSON Schema Draft 2020-12 |
4900-
| Rust | `jsonschema` crate | `jsonschema::is_valid()` + `jsonschema::validate()` |
4901-
| Java | `networknt/json-schema-validator` | Supports Draft 2020-12, bean validation alternative |
4902-
| C++ | `valijson` or `nlohmann/json-schema-validator` | Fewer options, but functional |
4903-
| C | No mature pure-C library | Recommend FFI to a C++ or Rust validator, or embed a lightweight subset |
4851+
No additional schema library is required beyond what the SDK already uses.
49044852

49054853
#### 12.8.6 Naming Convention
49064854

49074855
Follow each language's idiomatic casing for PreflightCheckResult and PreflightResult fields:
49084856

4909-
| Field (Protocol) | Python | TypeScript | Go | Rust | Java | C/C++ |
4910-
|------------------|--------|------------|-----|------|------|-------|
4911-
| `check` | `check` | `check` | `Check` | `check` | `check()` | `check` |
4912-
| `passed` | `passed` | `passed` | `Passed` | `passed` | `passed()` | `passed` |
4913-
| `error` | `error` | `error` | `Error` | `error` | `error()` | `error` |
4914-
| `valid` | `valid` | `valid` | `Valid` | `valid` | `valid()` | `valid` |
4915-
| `checks` | `checks` | `checks` | `Checks` | `checks` | `checks()` | `checks` |
4916-
| `requires_approval` | `requires_approval` | `requiresApproval` | `RequiresApproval` | `requires_approval` | `requiresApproval()` | `requires_approval` |
4917-
| `errors` (computed) | `errors` (property) | `errors` (readonly) | `Errors()` (method) | `errors()` (method) | `errors()` (method) | `errors()` (function) |
4857+
| Field (Protocol) | snake_case languages | camelCase languages | PascalCase languages |
4858+
|------------------|---------------------|--------------------|--------------------|
4859+
| `check` | `check` | `check` | `Check` |
4860+
| `passed` | `passed` | `passed` | `Passed` |
4861+
| `error` | `error` | `error` | `Error` |
4862+
| `valid` | `valid` | `valid` | `Valid` |
4863+
| `checks` | `checks` | `checks` | `Checks` |
4864+
| `requires_approval` | `requires_approval` | `requiresApproval` | `RequiresApproval` |
4865+
| `errors` (computed) | `errors` | `errors` | `Errors()` |
4866+
4867+
> **Convention:** snake_case (Python, Rust), camelCase (TypeScript, Java methods), PascalCase (Go exported fields). Other languages follow their idiomatic convention.
49184868
49194869
---
49204870

@@ -5185,7 +5135,7 @@ apcore supports three module definition methods to meet different scenario needs
51855135
| Dimension | Class-based (Class Definition) | Function-based (Functional) | External Binding (External Binding) |
51865136
|------|---------------------|------------------------|---------------------------|
51875137
| **Definition Method** | Inherit Module base class | `@module` / `module()` | YAML binding file |
5188-
| **Schema Source** | Pydantic Model / YAML | Type annotation auto-generation | YAML explicit definition / auto_schema |
5138+
| **Schema Source** | Native model / YAML | Type annotation auto-generation | YAML explicit definition / auto_schema |
51895139
| **Code Invasiveness** | High (need inherit base class) | Low (add decorator or function call) | Zero (no source code modification) |
51905140
| **Applicable Scenarios** | New module development | Existing function/method wrapping | Existing application zero-modification integration |
51915141
| **Lifecycle Hooks** | on_load / on_unload | Not supported | Not supported |
@@ -5194,14 +5144,13 @@ apcore supports three module definition methods to meet different scenario needs
51945144

51955145
**Cross-language Syntax Reference:**
51965146

5197-
| Language | Class-based | Function-based (Decorator) | Function-based (Function Call) | External Binding |
5147+
Each language SDK **should** provide idiomatic module definition syntax. The following illustrates the general patterns:
5148+
5149+
| Pattern | Class-based | Decorator/Attribute | Function Call | External Binding |
51985150
|------|------------|--------------------------|-------------------------|-----------------|
5199-
| Python | `class M(Module)` | `@module(id=...)` | `module(fn, id=...)` | YAML |
5200-
| TypeScript | `class M extends Module` | `@module({id: ...})` | `module(fn, {id: ...})` | YAML |
5201-
| Java | `class M implements Module` | `@Module(id=...)` | `Apcore.module(fn, id)` | YAML |
5202-
| Rust | `impl Module for M` | `#[module(id=...)]` | `apcore::module(id, fn)` | YAML |
5203-
| Go | `type M struct` + `Module` interface | — | `apcore.Module(id, fn)` | YAML |
5204-
| C | `apcore_module_t` struct | — | `apcore_module(id, fn)` | YAML |
5151+
| Description | Inherit/implement Module interface | Language-native annotation | Wrap existing callable | YAML binding file |
5152+
| Example (Python) | `class M(Module)` | `@module(id=...)` | `module(fn, id=...)` | YAML |
5153+
| Example (TypeScript) | `class M extends Module` | `@module({id: ...})` | `module(fn, {id: ...})` | YAML |
52055154

52065155
---
52075156

README.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -287,19 +287,29 @@ For a detailed multi-language guide, visit the **[Getting Started Guide](https:/
287287
```
288288

289289
```python
290-
from apcore import module, Registry, Executor
290+
import apcore
291291

292-
# 1. Create Registry
293-
registry = Registry()
292+
# Use the global client for easy registration and calling
293+
@apcore.module(id="math.add", description="Add two integers")
294+
def add(a: int, b: int) -> int:
295+
return a + b
294296

295-
# 2. Define module with @module decorator (Schema auto-inferred, auto-registered)
296-
@module(id="math.add", description="Add two integers", registry=registry)
297-
def add(a: int, b: int) -> dict:
298-
return {"sum": a + b}
297+
# Call directly
298+
print(apcore.call("math.add", {"a": 10, "b": 5})) # {'result': 15}
299+
```
300+
301+
Or use the explicit client:
302+
303+
```python
304+
from apcore import APCore
305+
306+
client = APCore()
307+
308+
@client.module(id="math.add")
309+
def add(a: int, b: int) -> int:
310+
return a + b
299311

300-
# 3. Call
301-
executor = Executor(registry=registry)
302-
print(executor.call("math.add", {"a": 10, "b": 5})) # {'sum': 15}
312+
print(client.call("math.add", {"a": 10, "b": 5}))
303313
```
304314

305315
=== "TypeScript"

SCOPE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ Use these scenarios to validate whether our boundaries are correct:
198198
- [ ] Schema and Meta files: Keep separated
199199
- [x] Existing application integration: **Core** (`module()` registration and external Schema binding are core standards)
200200
- [x] Framework adapters: **Won't Do** (independent repositories, apcore only provides adapter interface specification)
201-
- [x] API naming: **No prefix** (rely on language namespaces, except C language which uses `apcore_` prefix)
201+
- [x] API naming: **No prefix** (rely on language namespaces; languages without namespace mechanisms use `apcore_` prefix)
202202

203203
## 9. Document Structure
204204

0 commit comments

Comments
 (0)