apcore — AI-Perceivable Core¶
A schema-enforced module framework where every interface is inherently perceivable by AI.
A schema-driven module development framework that makes every interface naturally perceivable and understandable by AI.
apcore is a protocol specification. Language implementations are maintained in separate repositories — see Implementations.
Table of Contents¶
- What is apcore?
- Why AI-Perceivable?
- Core Principles
- Architecture Overview
- Quick Start
- Module Development
- Class-based Modules
- @module Decorator
- module() Function Call
- External Binding (Zero Code Modification)
- Schema System
- Three-Layer Metadata Design
- Module Annotations
- LLM Extension Fields
- Context Object
- ACL Access Control
- Middleware
- Configuration
- Observability
- Error Handling
- Cross-Language Support
- Relationship with Other Tools
- Implementations
- Ecosystem
- Documentation Index
- Contributing
- License
What is apcore?¶
apcore is a universal module development framework that makes every module naturally perceivable and understandable by AI through enforced Schema definitions.
┌─────────────────────────────────────────────────────────────┐
│ apcore — AI-Perceivable Core │
│ │
│ Universal framework + Enforced AI-Perceivable support │
│ - Directory as ID (zero-config module discovery) │
│ - Schema-driven (input/output mandatory) │
│ - ACL / Observability / Middleware │
└─────────────────────────────────────────────────────────────┘
↓ Modules callable by
┌──────────┬──────────┬──────────┬──────────┐
│ │ │ │ │
Legacy Code AI/LLM HTTP API CLI Tool MCP Server
(import) (understands) (REST) (terminal) (Claude)
Not just an AI framework, but a universal framework that is naturally AI-Perceivable.
Core Problem¶
Traditional module development faces a fundamental contradiction:
Traditional modules: Code can call, but AI cannot understand
AI-Perceivable modules: Code can call, AI can also perceive and understand
AI has become an important caller in software systems, but most modules lack AI-understandable metadata. apcore fundamentally solves this by enforcing input_schema / output_schema / description.
One-Sentence Summary¶
apcore solves how to build modules (development framework), not how to call tools (communication protocol). Once modules are built, they can be called by code / AI / HTTP / CLI / MCP or any other means.
Why AI-Perceivable?¶
Real-World Scenarios¶
| Scenario | Without apcore | With apcore |
|---|---|---|
| LLM calling your business functions | Manually write tool descriptions, map parameters | Schema auto-provided, LLM understands directly |
| New team members onboarding | Read source code, guess parameters | Clear from Schema + annotations |
| Cross-team module reuse | Outdated docs, unclear interfaces | Schema is doc, enforced validation |
| Security audit | Manually trace call relationships | ACL + call chain auto-tracked |
| Expose as MCP Server | Rewrite interface definitions | Adapter reads Schema directly |
Design Decision¶
Reality: AI has become a key caller in software systems
Decision: Enforce input_schema / output_schema / description
Result: Modules understandable by both humans and AI, no extra cost
Core Principles¶
| Principle | Description |
|---|---|
| Schema-Driven | All modules enforce input_schema / output_schema / description |
| Directory as ID | Directory path auto-maps to module ID, zero config |
| AI-Perceivable | Schema enables AI/LLM perception and understanding—a design requirement, not optional |
| Universal Framework | Modules callable by code/AI/HTTP/CLI or any other means |
| Progressive Integration | Existing code gains AI-Perceivable capability via decorators, function calls, or YAML binding |
| Cross-Language Spec | Language-agnostic protocol specification, any language can implement conformant SDK |
Differences from Traditional Frameworks¶
| Traditional Frameworks | apcore | |
|---|---|---|
| Schema | Optional | Enforced |
| AI-Perceivable | Not guaranteed | Guaranteed |
| Module Discovery | Manual registration | Auto-discovery from directory |
| Input Validation | Implement yourself | Framework automatic |
| Behavior Annotations | None | readonly / destructive / requires_approval etc. |
| Call Tracing | Implement yourself | trace_id auto-propagated |
Architecture Overview¶
apcore's architecture consists of two orthogonal dimensions: Framework Technical Architecture (vertical) and Business Layering Recommendations (horizontal).
Framework Technical Architecture (Vertical)¶
The technical layers of the framework itself, defining the complete flow from module registration to execution:
┌─────────────────────────────────────────────────┐
│ Application Layer │
│ HTTP API / CLI / MCP Server / Custom Interface│
└─────────────────────┬───────────────────────────┘
↓ calls
┌─────────────────────────────────────────────────┐
│ Execution Layer │
│ ACL check → Input validation → Middleware chain│
│ → Execute → Output validation │
└──────────┬──────────────────────────────────────┘
↓ lookup module
┌─────────────────────────────────────────────────┐
│ Registry Layer │
│ Scan & discover → ID mapping → Interface │
│ validation → Module storage │
└──────────┬──────────────────────────────────────┘
↓ read
┌─────────────────────────────────────────────────┐
│ Module Layer │
│ User-written business modules (conforming to │
│ Module interface specification) │
└─────────────────────────────────────────────────┘
Business Layering Recommendations (Horizontal)¶
Under the extensions/ directory, modules should be organized by responsibility (enforced by ACL):
extensions/
├── api/ # API Layer: Handle external requests
│ └── ACL: Can only call orchestrator.*
│
├── orchestrator/ # Orchestration Layer: Compose business flows
│ └── ACL: Can only call executor.* and common.*
│
├── executor/ # Execution Layer: Concrete business operations
│ └── ACL: Can call common.*, can connect to external systems
│
└── common/ # Common Layer: Shared utilities and helpers
└── ACL: Read-only operations, called by all layers
Key Points: - Framework technical architecture (Application → Execution → Registry → Module) is apcore's implementation mechanism - Business layering (api → orchestrator → executor → common) is a best practice recommendation, enforced through ACL configuration - The two are orthogonal: any business layer module (api/orchestrator/executor/common) goes through the same framework layer processing
Execution Flow¶
A module call goes through the following steps:
executor.call("executor.email.send_email", inputs, context)
│
├─ 1. Context processing: Create/update call context (trace_id, caller_id, call_chain)
├─ 2. Lookup module: Find target module from Registry
├─ 3. ACL check: Verify caller has permission to call target module
├─ 4. Input validation: Validate input parameters against input_schema
├─ 5. Middleware before: Execute middleware before() hooks in sequence
├─ 6. Module execution: Call module.execute(inputs, context)
├─ 7. Output validation: Validate output result against output_schema
├─ 8. Middleware after: Execute middleware after() hooks in reverse order
│
└─ Return result
Directory as ID¶
Module IDs are automatically generated from relative paths under the module root directory (default root is extensions/, multiple roots can be configured):
File path: Canonical ID:
extensions/api/handler/user.py → api.handler.user
extensions/executor/email/send_email.py → executor.email.send_email
extensions/common/util/validator.py → common.util.validator
Rules:
1. Remove module root prefix (default `extensions/`)
2. Remove file extension
3. Replace `/` with `.`
4. Must match: ^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$
5. Maximum length: 128 characters
**Multiple Roots and Namespaces**
- If multiple module root directories are configured, each root directory automatically uses the directory name as a **namespace**, ensuring Module ID uniqueness within the same Registry.
- For example: `extensions_roots: ["./extensions", "./plugins"]` → `extensions.executor.email.send_email`, `plugins.my_tool`.
- Automatic namespacing can be overridden with explicit configuration (e.g., `{root: "./extensions", namespace: "core"}` → `core.executor.email.send_email`).
- Single root mode has no namespace by default (backward compatible); in multi-root mode, at most one root can set `namespace: ""` to omit the prefix.
**Cross-Project Conflicts**
- Same IDs from different projects **will not conflict**, unless they are merged into the same Registry / call domain (e.g., unified gateway or shared executor).
Quick Start¶
Detailed documentation: Registry API | Executor API | Context Object
from apcore import Module, Registry, Executor, Context
from pydantic import BaseModel, Field
# 1. Define module (Schema-driven)
class GreetInput(BaseModel):
name: str = Field(..., description="User name")
class GreetOutput(BaseModel):
message: str
class GreetModule(Module):
"""Generate greeting message"""
input_schema = GreetInput
output_schema = GreetOutput
def execute(self, inputs: dict, context: Context) -> dict:
return {"message": f"Hello, {inputs['name']}!"}
# 2. Register & call
registry = Registry()
registry.register("executor.greet", GreetModule())
executor = Executor(registry=registry)
result = executor.call("executor.greet", {"name": "World"})
print(result) # {"message": "Hello, World!"}
Project Directory Structure¶
my-project/
├── apcore.yaml # Framework configuration
├── extensions/ # Module directory (directory path = module ID)
│ ├── api/ # API layer
│ ├── orchestrator/ # Orchestration layer
│ └── executor/ # Execution layer
├── schemas/ # Schema definitions (YAML, shared across languages)
└── acl/ # Permission configuration
Module Development¶
Detailed definitions: Module Interface | Creating Modules Guide
apcore provides four ways to define modules, suitable for different scenarios:
1. Class-based Modules¶
The most complete approach, supporting all features:
# extensions/executor/email/send_email.py
# Module ID auto-generated: executor.email.send_email
from apcore import Module, ModuleAnnotations, Context
from pydantic import BaseModel, Field
class SendEmailInput(BaseModel):
"""LLM understands what parameters are needed through this Schema"""
to: str = Field(..., description="Recipient email address")
subject: str = Field(..., description="Email subject")
body: str = Field(..., description="Email body")
class SendEmailOutput(BaseModel):
"""LLM understands what is returned through this Schema"""
success: bool
message_id: str = None
class SendEmailModule(Module):
"""Send email module
Detailed documentation:
- Supports text and HTML format emails
- Uses SMTP protocol to connect to external mail server
- Configuration items: smtp_host, smtp_port, smtp_user, smtp_pass
Usage example:
Input: {"to": "[email protected]", "subject": "Hello", "body": "World"}
Output: {"success": true, "message_id": "msg_123"}
Notes:
- SMTP server information must be configured in the configuration file
- Gmail limits 500 emails/day, other providers may have different limits
- EmailSendError exception will be raised on send failure
"""
# Core layer (must be defined)
input_schema = SendEmailInput
output_schema = SendEmailOutput
description = "Send email to specified recipient. Uses SMTP protocol, non-idempotent operation, requires mail server configuration."
# Optional: Detailed documentation (for complex modules)
documentation = """
# Features
Send emails via SMTP protocol, supporting plain text and HTML formats.
## Configuration Requirements
- SMTP server information must be configured in apcore.yaml
- Valid SMTP authentication credentials required
## Use Cases
- Send notification emails, verification codes, reports
## Limitations
- Gmail: 500 emails/day
- Attachment size: ≤25MB
"""
# Annotation layer (optional, type-safe)
annotations = ModuleAnnotations(
readonly=False, # Has side effects
destructive=False, # Won't delete/overwrite data
idempotent=False, # Repeated calls will send repeatedly
requires_approval=True, # Requires user confirmation
open_world=True, # Connects to external system (SMTP)
)
tags = ["email", "notification"]
def execute(self, inputs: dict, context: Context) -> dict:
validated = SendEmailInput(**inputs)
# ... send email logic ...
return SendEmailOutput(success=True, message_id="msg_123").model_dump()
This module automatically has:
- LLM-understandable Schema and behavior annotations
- Auto-generated ID (executor.email.send_email)
- Input/output validation
- Call chain tracing, observability
2. @module Decorator¶
Suitable for scenarios where source code can be modified, one-line integration:
# Before: Plain function
def send_email(to: str, subject: str, body: str) -> dict:
"""Send email"""
return {"success": True, "message_id": "msg_123"}
# After: Add one line decorator, automatically becomes an apcore module
from apcore import module
@module(id="email.send", tags=["email"])
def send_email(to: str, subject: str, body: str) -> dict:
"""Send email"""
return {"success": True, "message_id": "msg_123"}
# Schema automatically inferred from type annotations
3. module() Function Call¶
Suitable for scenarios where you don't want to modify source code, completely non-invasive to existing code:
from apcore import module
# Existing business code, no modification needed
class EmailService:
def send(self, to: str, subject: str, body: str) -> dict:
"""Send email"""
return {"success": True}
service = EmailService()
module(service.send, id="email.send") # Register as apcore module
4. External Binding (Zero Code Modification)¶
Suitable for scenarios where source code cannot be modified (third-party libraries, legacy systems, etc.), pure YAML configuration:
# bindings/email.binding.yaml
bindings:
- module_id: "email.send"
target: "myapp.services.email:send_email" # Callable object path
description: "Send email"
auto_schema: true # Auto-generate Schema from type annotations
annotations:
open_world: true
requires_approval: true
tags: ["email"]
Comparison of Four Approaches¶
| Approach | Code Invasiveness | Use Case | Schema Definition |
|---|---|---|---|
| Class-based | High (write new class) | New module development | Manual definition (most complete) |
@module Decorator |
Low (add one line) | Modifiable code | Inferred from type annotations |
module() Function Call |
Very low (don't modify original function) | Existing classes/methods | Inferred from type annotations |
| External Binding | Zero | Cannot modify source code scenarios | Auto-inferred or manually specified |
Schema System¶
Detailed definitions: Schema Definition Guide | ModuleAnnotations API
Three-Layer Metadata Design¶
Each module's metadata is divided into three layers, progressing from required to optional:
┌──────────────────────────────────────────────────┐
│ Core Layer (REQUIRED) │
│ input_schema / output_schema / description │
│ → AI understands "what this module does" │
│ │
│ + documentation (OPTIONAL, detailed docs) │
│ → AI understands "detailed use cases and │
│ constraints" │
├──────────────────────────────────────────────────┤
│ Annotation Layer (OPTIONAL, type-safe) │
│ annotations / examples / tags / version │
│ → AI understands "how to use correctly" │
├──────────────────────────────────────────────────┤
│ Extension Layer (OPTIONAL, free dictionary) │
│ metadata: dict[str, Any] │
│ → Custom requirements (framework doesn't │
│ validate) │
└──────────────────────────────────────────────────┘
Description and Documentation Fields¶
Borrowing from Claude Skill's Progressive Disclosure design, apcore uses two fields to organize module documentation:
| Field | Required | Length Limit | Markdown | Purpose |
|---|---|---|---|---|
description |
Required | ≤200 characters | No | Brief module function description for AI quick matching and understanding |
documentation |
Optional | ≤5000 characters | Yes | Detailed documentation including use cases, constraints, configuration requirements |
- Module discovery phase: AI reads all modules'
description, quickly determines candidate modules - Call decision phase: AI loads
documentationon-demand, learns detailed usage and constraints
Complete format rules and correspondence with Claude Skill / OpenAPI: see Protocol Specification §4.8. Code examples: see Class-based Modules above.
Schema Definition¶
Schema is based on JSON Schema Draft 2020-12, supports YAML format definition (shared across languages). Schema files are placed in the schemas/ directory, with paths corresponding to module IDs.
Complete Schema format and YAML examples: see Schema Definition Guide | Protocol Specification §4.
Module Annotations¶
Annotations describe module behavior characteristics, helping AI make safer call decisions:
| Annotation | Type | Description | AI Behavior Impact |
|---|---|---|---|
readonly |
bool | No side effects, read-only operation | AI can safely call autonomously |
destructive |
bool | May delete or overwrite data | AI should request user confirmation before calling |
idempotent |
bool | Repeated calls have same result | AI can safely retry |
requires_approval |
bool | Requires explicit user consent | AI must wait for user approval |
open_world |
bool | Connects to external systems | AI should inform user of external interaction |
# Read-only query - AI can call autonomously
annotations = ModuleAnnotations(readonly=True)
# Delete operation - AI needs to request confirmation
annotations = ModuleAnnotations(destructive=True, requires_approval=True)
# External API call - AI needs to inform user
annotations = ModuleAnnotations(open_world=True, idempotent=True)
LLM Extension Fields¶
Fields with x- prefix in Schema are LLM-specific extensions, don't affect standard JSON Schema validation:
| Field | Description | Example |
|---|---|---|
x-llm-description |
Extended description for LLM (more detailed than description) | "User's login password, at least 8 characters" |
x-examples |
Example values to help LLM understand format | ["[email protected]"] |
x-sensitive |
Mark sensitive fields (password, API Key, etc.) | true |
x-constraints |
Business constraints described in natural language | "Must be a registered user" |
x-deprecated |
Deprecation information | {"since": "2.0", "use": "new_field"} |
Complete usage and examples: see Schema Definition Guide | Protocol Specification §4.3.
Context Object¶
Context is the execution context that runs through the entire call chain, carrying tracing, permissions, and shared data:
class Context:
trace_id: str # Call trace ID (UUID v4; W3C trace-id compatible in distributed scenarios)
caller_id: str | None # Caller module ID (None for top-level calls)
call_chain: list[str] # Call chain (accumulated in call order)
executor: Executor # Executor reference (entry point for inter-module calls)
identity: Identity # Caller identity
data: dict # Shared data (reference-shared within call chain)
Call Chain Propagation¶
# Top-level call
context = Context(trace_id="abc-123", identity=Identity(id="user_1", roles=["admin"]))
# Module A is called
# trace_id: "abc-123" ← Stays the same
# caller_id: None ← No caller at top level
# call_chain: ["module_a"]
# Module A internally calls Module B
result = context.executor.call("module_b", inputs, context)
# trace_id: "abc-123" ← Stays the same
# caller_id: "module_a" ← Caller is module_a
# call_chain: ["module_a", "module_b"]
# Module B internally calls Module C
# trace_id: "abc-123" ← Same trace_id for entire chain
# caller_id: "module_b"
# call_chain: ["module_a", "module_b", "module_c"]
Key Feature: context.data is reference-shared throughout the entire call chain, allowing modules to pass intermediate results and implement pipeline-style data flow.
ACL Access Control¶
Detailed definitions: ACL Configuration Guide | Protocol Specification §6
ACL (Access Control List) controls which modules can call which modules, default deny:
# acl/global_acl.yaml
rules:
# API layer can only call orchestration layer
- callers: ["api.*"]
targets: ["orchestrator.*"]
effect: allow
# Orchestration layer can call execution layer
- callers: ["orchestrator.*"]
targets: ["executor.*"]
effect: allow
# Forbid cross-layer calls (API directly calling execution layer)
- callers: ["api.*"]
targets: ["executor.*"]
effect: deny
# System internal modules unrestricted
- callers: ["@system"]
targets: ["*"]
effect: allow
default_effect: deny # Default deny when no rules match
audit:
enabled: true
log_level: info
include_denied: true
Special Caller Identifiers¶
| Identifier | Description |
|---|---|
@external |
Top-level external call (HTTP request, CLI command, etc.) |
@system |
Framework internal call |
* |
Wildcard, matches all |
Conditional Rules¶
rules:
- callers: ["api.*"]
targets: ["executor.payment.*"]
effect: allow
conditions:
identity_types: ["user"] # Only user identity
roles: ["admin", "finance"] # Only admin or finance roles
max_call_depth: 5 # Maximum call depth
Middleware¶
Detailed definitions: Middleware Guide
Middleware uses the Onion Model, allowing custom logic to be inserted before and after module execution:
Request → [MW1.before → [MW2.before → [MW3.before →
[Module.execute()]
← MW3.after] ← MW2.after] ← MW1.after] ← Response
class LoggingMiddleware(Middleware):
def before(self, module_id: str, inputs: dict, context: Context) -> dict:
log.info(f"Calling {module_id} with trace_id={context.trace_id}")
return inputs # Can modify inputs
def after(self, module_id: str, inputs: dict, output: dict, context: Context) -> dict:
log.info(f"Result from {module_id}: success")
return output # Can modify output
def on_error(self, module_id: str, inputs: dict, error: Exception, context: Context):
log.error(f"Error in {module_id}: {error}")
# Optional: Convert exception, trigger alerts, etc.
Typical middleware scenarios: logging, performance monitoring, caching, rate limiting, retry, auditing.
Configuration¶
The framework is centrally configured through apcore.yaml:
# apcore.yaml
version: "1.0.0"
project:
name: "my-ai-project"
version: "0.1.0"
# Module discovery (single root mode, backward compatible)
extensions:
root: "./extensions" # Module root directory
auto_discover: true # Auto-scan and discover
lazy_load: true # Lazy load (load module only on first call)
max_depth: 8 # Maximum directory depth
# Or: Multi-root mode (namespace isolation)
# extensions:
# roots:
# - root: "./extensions"
# namespace: "core" # Explicit namespace → core.executor.email.send_email
# - "./plugins" # Auto namespace → plugins.my_tool
# Schema loading
schema:
root: "./schemas"
strategy: "yaml_first" # yaml_first | native_first | yaml_only
validation:
strict: true # Strict validation mode
coerce_types: true # Automatic type coercion
# Access control
acl:
root: "./acl"
default_effect: "deny" # Default deny
audit:
enabled: true
# Logging
logging:
level: "info" # trace | debug | info | warn | error | fatal
format: "json" # json | text
# Observability
observability:
tracing:
enabled: true
sampling_rate: 1.0 # 1.0 = full collection, 0.1 = 10% sampling
exporter: "stdout" # stdout | otlp | jaeger
metrics:
enabled: true
exporter: "prometheus"
# Middleware
middleware:
- class: "myapp.middleware.LoggingMiddleware"
priority: 100
- class: "myapp.middleware.CachingMiddleware"
priority: 50
config:
ttl: 300
Observability¶
apcore has built-in three pillars of observability, compatible with OpenTelemetry:
Tracing¶
trace_idis automatically generated and propagated through the call chain- Span naming convention:
apcore.{component}.{operation} - Supports export to stdout / OTLP / Jaeger
Logging¶
- Structured logging, automatically includes
trace_id - Fields marked with
x-sensitiveare automatically redacted (e.g., passwords show as***REDACTED***) - Executor automatically provides
context.redacted_inputs, middleware and logs should use redacted data
Metrics¶
| Metric Name | Type | Description |
|---|---|---|
apcore_module_calls_total |
Counter | Total module calls |
apcore_module_duration_seconds |
Histogram | Module execution duration distribution |
apcore_module_errors_total |
Counter | Total module errors |
Error Handling¶
apcore defines a unified error format and standard error codes:
Error Format¶
{
"code": "SCHEMA_VALIDATION_ERROR",
"message": "Input validation failed",
"details": {"field": "email", "reason": "invalid format"},
"cause": null,
"trace_id": "abc-123",
"timestamp": "2026-01-01T00:00:00Z"
}
Standard Error Codes¶
| Category | Error Code | Description | Retryable |
|---|---|---|---|
| Module | MODULE_NOT_FOUND |
Module does not exist | No |
| Module | MODULE_EXECUTE_ERROR |
Execution exception | Depends |
| Module | MODULE_TIMEOUT |
Execution timeout | Yes |
| Schema | SCHEMA_VALIDATION_ERROR |
Input/output validation failed | No |
| Schema | SCHEMA_NOT_FOUND |
Schema file does not exist | No |
| ACL | ACL_DENIED |
Permission denied | No |
| Binding | BINDING_INVALID_TARGET |
Invalid binding target path | No |
| Binding | BINDING_CALLABLE_NOT_FOUND |
Bound callable object not found | No |
| General | GENERAL_INTERNAL_ERROR |
Internal error | Yes |
Cross-Language Support¶
apcore is a language-agnostic framework specification. Canonical IDs are automatically adapted to local naming conventions in different languages:
Canonical ID (universal): executor.email.send_email
Local representation:
Python: executor/email/send_email.py class SendEmailModule
Rust: executor/email/send_email.rs struct SendEmailModule
Go: executor/email/send_email.go type SendEmailModule
Java: executor/email/SendEmail.java class SendEmailModule
TypeScript: executor/email/sendEmail.ts class SendEmailModule
ID Mapping Rules¶
- Automatic language detection (based on file extension)
- Case conversion (PascalCase ↔ snake_case ↔ camelCase)
- Path separator normalization (
/vs::vs.) - Supports manual override (
id_mapconfiguration)
Conformance Levels¶
Any language SDK implementation can choose different conformance levels:
| Level | Scope | Includes |
|---|---|---|
| Level 0 (Core) | Minimally viable | ID mapping, Schema loading, Registry, Executor |
| Level 1 (Standard) | Production ready | + ACL, middleware, error handling, observability |
| Level 2 (Full) | Complete implementation | + Hot reload, distributed execution, advanced monitoring |
Reference Implementation: apcore-python
Relationship with Other Tools¶
apcore vs MCP¶
| apcore | MCP | |
|---|---|---|
| Positioning | Development framework | Communication protocol |
| Solves | How to build modules | How to call tools |
| Focus | Code organization, Schema, ACL, observability | Transport format, RPC |
| Relationship | apcore modules can be exposed as MCP Server | MCP is one exposure method |
apcore vs LangChain / LlamaIndex¶
| apcore | LangChain etc. | |
|---|---|---|
| Positioning | Module development framework | LLM application development framework |
| Focus | Module standardization, Schema, permissions | Chaining, Prompt, RAG |
| Relationship | Complementary — apcore modules can serve as LangChain Tools |
apcore vs CrewAI / AutoGen¶
| apcore | CrewAI etc. | |
|---|---|---|
| Positioning | Module development framework | Agent orchestration framework |
| Focus | Standardizing individual modules | Multi-agent collaboration strategies |
| Relationship | Complementary — Agents can call apcore modules |
In short: apcore focuses on building standardized, AI-understandable modules, complementary rather than competitive with upper-layer AI protocols/frameworks.
Implementations¶
Language SDK implementations of the apcore protocol specification:
| Language | Repository | Features | Install |
|---|---|---|---|
| Python | apcore-python | Schema validation, Registry, Executor, @module decorator, YAML bindings, ACL, Middleware, Observability, Async support | pip install apcore |
Interested in implementing apcore for another language? See the Protocol Specification and Conformance Definition.
Ecosystem¶
The apcore ecosystem uses a core + independent adapters architecture. The core does not include any framework-specific implementations; adapters are developed in independent repositories by official or community contributors.
Adapter Types¶
| Type | Examples | Description |
|---|---|---|
| Web Frameworks | apcore-fastapi, apcore-flask, apcore-express |
Expose modules as HTTP APIs |
| AI Protocols | apcore-mcp, apcore-openai-tools |
Expose modules as AI tools |
| RPC | apcore-grpc, apcore-thrift |
Expose modules as RPC services |
All adapters are built on the core's module() and External Binding mechanisms.
Development guide: see Adapter Development Guide.
Documentation Index¶
Core Documentation¶
| Document | Description |
|---|---|
| Protocol Specification | Complete framework specification (RFC 2119 Conformant) |
| Scope Definition | Responsibility boundaries (what's in/out of scope) |
Concepts & Architecture¶
| Document | Description |
|---|---|
| Core Concepts | Design philosophy and core concepts explained |
| Architecture Design | Internal architecture, component interaction, memory model |
API Reference¶
| Document | Description |
|---|---|
| Module Interface | Module interface definition |
| Context Object | Execution context |
| Registry API | Registry API |
| Executor API | Executor API |
Usage Guides¶
| Document | Description |
|---|---|
| Creating Modules | Module creation tutorial (including four approaches) |
| Schema Definition | Complete Schema usage |
| ACL Configuration | Access control configuration |
| Middleware | Middleware development |
| Adapter Development | Framework adapter development |
| Testing Modules | Module testing guide |
| Multi-Language Development | Cross-language development guide |
Specification Documents¶
| Document | Description |
|---|---|
| Type Mapping | Cross-language type mapping |
| Conformance Definition | Implementation conformance levels |
| Algorithm Reference | Core algorithm summary (including namespace, redaction, etc.) |
Contributing¶
Contributions are welcome in the following forms:
- Specification Feedback: Suggest improvements to the protocol specification in Issues
- SDK Implementation: Implement SDKs for other languages based on Protocol Specification
- Adapter Development: Develop adapters for web frameworks or AI protocols
- Documentation Improvements: Fix, translate, or supplement documentation
License¶
Apache 2.0