Install
$ agentstack add skill-dungnotnull-vertical-farming-mobile-container-agent-skill-vertical-farming-mobile-container-agent-skill ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
SKILL.md — Skill Registry Documentation
> Project: vertical-farming-mobile-container (vfmc) > Version: 1.1.0 > Purpose: The single, authoritative reference for how skills are > registered, resolved, executed, and validated in the vfmc agent runtime.
This document describes the modular skill-registry architecture that powers the vertical-farming harness. The runtime lives in src/vfmc/agents/; the declarative skill specs also exist as markdown in skills/ for human review and LLM grounding.
1. Architecture Overview
┌──────────────────────────────────────────────┐
│ Orchestrator │
│ (src/vfmc/agents/orchestrator.py) │
└───────────────┬──────────────────────────────┘
│
┌───────────────────────┼───────────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Router │ │ HookRegistry │ │ ToolRegistry │
│ (chain-of- │ │ (lifecycle hooks)│ │ (JSON-schema │
│ thought) │ │ │ │ tools) │
└──────┬───────┘ └────────┬─────────┘ └──────┬───────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ SkillRegistry │
│ resolves SkillBase instances by name + validates prereqs │
└──────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Skills (SkillBase subclasses) │
│ sub-gather-requirements → sub-evidence-collector → │
│ sub-core-analysis → sub-knowledge-updater → sub-advisor │
└─────────────────────────────────────────────────────────────┘
Design principles
- Modular skill-registry pattern. Adding a skill is a registration, not
a refactor. Each skill is a self-contained SkillBase subclass with a declared input/output JSON schema and a quality gate.
- Chain-of-thought router. The router emits an explicit reasoning trace
that selects which skills to run, in what order, and which to skip.
- Tools as the only I/O boundary. Sub-agents never touch the network or
filesystem directly; they call schema-validated tools via ToolRegistry.
- Lifecycle hooks cross-cut every step. Logging, metrics, degradation,
token-budget guards, state sync, and audit trail are reusable hooks.
- Fail-fast configuration.
src/vfmc/config/validates the full config
(env vars, LLM params, feature flags) at load time.
- Graceful degradation, never fabrication. Every degraded run emits an
explicit LIMITATION NOTICE; the universal gates (U1–U6) and domain gates (G1–G4) are enforced after the pipeline.
2. Core Types
2.1 SkillBase (abstract contract)
class SkillBase(ABC):
name: str # unique registry key, e.g. "sub-core-analysis"
step: str # harness step number, e.g. "3"
description: str
category: str # intake | evidence | domain | knowledge | synthesis | general
requires: list[str] # prerequisite skill names
input_schema: dict # JSON Schema for the skill's inputs
output_schema: dict # JSON Schema for the skill's outputs
feature_flag: str | None # FeatureFlags attribute gating this skill
def execute(self, context: AgentContext) -> SkillResult: ...
def evaluate_gates(self, context, result) -> list[dict]: ...
2.2 SkillResult
{
"skill_name": "sub-core-analysis",
"step": "3",
"status": "ok", // ok | degraded | error
"output": { /* skill-specific */ },
"gate_passed": true,
"gate_failures": [],
"degradation_level": 0,
"tokens_used": 6000,
"elapsed_ms": 42.5,
"error": null
}
2.3 AgentContext
The mutable cross-step state shared by the orchestrator and every sub-agent:
| Field | Type | Purpose | |-------|------|---------| | run_id | str | Unique run identifier | | user_query | str | The originating user message | | language | str | Detected output language (en/vi) | | climate_zone, crop_type, racking_layers | enum/int | Parsed requirements | | requirements | Requirements | Structured intake output | | evidence | EvidenceBundle | Step-2 evidence bundle | | analysis | AnalysisResult | Step-3 simulation result | | knowledge_citations | list[dict] | Step-4 citations | | degradation_level | int (0–4) | Current degradation level | | limitation_banner | str | Auto-set when degraded | | gate_failures | list[dict] | All gate failures this run | | logs, events | list | Structured log + event streams | | budget | TokenBudget | Token accounting | | extra | dict | Hook scratchpad (metrics, audit) |
3. Registered Skills
The default registry (default_registry) registers five canonical skills mirroring skills/sub-*.md. They run in order; each declares its prerequisites.
| Step | Skill name | Category | Requires | Feature flag | Quality gates | |------|------------|----------|----------|--------------|---------------| | 1 | sub-gather-requirements | intake | — | — | intake.objectconfirmed | | 2 | sub-evidence-collector | evidence | sub-gather-requirements | websearchenabled | evidence.minsources | | 3 | sub-core-analysis | domain | sub-gather-requirements, sub-evidence-collector | simulationengineenabled | G1, G2, G3 | | 4 | sub-knowledge-updater | knowledge | sub-core-analysis | knowledgecrawlenabled | knowledge.minacademic | | 5 | sub-advisor | synthesis | sub-core-analysis, sub-knowledge-updater | — | verdictvalid, U2, G4 |
Input/Output JSON Schemas (summary)
sub-gather-requirements
- Input:
{ "user_query": string } - Output: `{ "objectofanalysis": string, "climatezone": string, "croptype": string,
"rackinglayers": integer, "language": string, "powerbudgetkw": number|null, "waterbudgetlday": number|null }`
sub-evidence-collector
- Input:
{ "requirements": object } - Output: `{ "currentdata": array, "authoritativedocs": array, "recent_news": array,
"referencebenchmarks": array, "webstatus": string }`
sub-core-analysis
- Input: `{ "climatezone": string, "croptype": string, "racking_layers": integer,
"language": string }`
- Output: `{ "verdict": string, "ledplan": array, "climatecontrol": object,
"hydroponicdesign": object, "resourceefficiency": object, "scenarios": array }`
sub-knowledge-updater
- Input:
{ "keywords": array, "limit": integer } - Output:
{ "citations": array, "coverage": string, "gaps": array, "search_status": string }
sub-advisor
- Input:
{ "analysis": object, "citations": array } - Output: `{ "verdict": string, "evidencechain": array, "keyrisks": array,
"disclosure": array, "recommendedactions": array, "scenarios": array, "degradationlevel": integer }`
Full JSON Schemas are in assets/schemas/skill.schema.json (for the skill contract) and the per-skill input_schema/output_schema declared on each SkillBase subclass.
4. Registration, Resolution, Execution, Validation
4.1 Registration
from vfmc.agents.registry import default_registry
registry = default_registry() # pre-loads the 5 canonical skills
# Or register a custom skill:
registry.register(MyCustomSkill(tools=registry.tools, hooks=registry.hooks))
# Or lazily via factory:
registry.register_factory("my-skill", lambda t, h: MyCustomSkill(tools=t, hooks=h))
Duplicate names raise ValueError. Prerequisites are validated by registry.validate_prerequisites(), which returns a list of any missing prerequisite skills.
4.2 Resolution
skill = registry.get("sub-core-analysis") # None if missing
skill = registry.require("sub-core-analysis") # raises KeyError if missing
4.3 Execution
The orchestrator is the only entry point that executes skills:
from vfmc.agents import Orchestrator
report = Orchestrator().run("analyze arctic lettuce 4 layers 10kw")
The orchestrator:
- Builds a fresh
AgentContext. - Asks the router for the execution plan.
- Fires
pre_stephooks, runs the skill (with retries), firespost_step/
on_step_error / on_degradation hooks.
- Runs the universal quality gates U1–U6 after the pipeline.
- Fires
on_finalize+post_runhooks. - Returns a serializable
RunReport.
4.4 Validation
Three layers of validation run on every invocation:
- Per-skill quality gates (e.g.
G1.led_per_stage,U2.disclosure_first)
evaluate after each skill. Each gate has an auto-fix callable and a retry cap (max_retries, default 2). Failures are recorded on the context and surfaced in SkillResult.gate_failures.
- Universal quality gates U1–U6 run at the harness level after the
pipeline (see §5).
- Schema validation for tool inputs (
Tool.validate_input) and the
assets/schemas/*.schema.json files (validated by scripts/validate_schemas.py and the test suite).
5. Quality Gates
Universal gates (U1–U6) — enforced by the orchestrator
| Gate | Check | Enforcement | |------|-------|-------------| | U1 | ≥3 sources cited, ≥1 academic/authoritative | record failure if not met | | U2 | Disclosure present before recommendation | record failure if not met | | U3 | Evidence hierarchy (tier label) per source | record failure if not met | | U4 | Language matches detected user preference | record failure if not met | | U5 | All output sections present | record failure if not met | | U6 | Every claim traceable to ≥1 source | record failure if not met |
Domain gates (G1–G4) — enforced by the relevant sub-skill
| Gate | Skill | Check | |------|-------|-------| | G1 | sub-core-analysis | LED spectrum & DLI per growth stage (≥3 stages, blue/red/far-red) | | G2 | sub-core-analysis | Climate control targets stated (VPD, CO2, T, RH) | | G3 | sub-core-analysis | Resource efficiency quantified (water L/kg, energy kWh/kg, yield kg/m2/yr) | | G4 | sub-advisor | ≥2 Tier-1 authoritative sources cited |
Each gate: on failure, run auto-fix; after 2 failed retries, record the limitation explicitly and continue. The harness never silently proceeds.
6. Tools (the I/O boundary)
Tools are registered in ToolRegistry and gated by feature flags. Each tool declares a JSON Schema for its input and a deterministic handler returning a plain dict (never raising on expected failures).
| Tool | Category | Side effects | Feature flag | Description | |------|----------|--------------|--------------|-------------| | simulate_farm | simulation | no | simulationengineenabled | Run the deterministic engine for climate×crop | | knowledge_search | knowledge | no | knowledgecrawlenabled | Search SECOND-KNOWLEDGE-BRAIN.md | | knowledge_append | knowledge | yes | knowledgeautoappend | Append entries to the knowledge base | | knowledge_crawl | knowledge | yes | knowledgecrawlenabled | Crawl ArXiv/Scholar/RSS | | web_search | web | no | websearchenabled | Live web search (synthetic offline fallback) | | web_fetch | web | no | webfetchenabled | Fetch URL content | | compile_evidence | knowledge | no | — | Build an EvidenceBundle from raw sources | | climate_profile | reference | no | — | Default climate profile for a zone | | crop_profile | reference | no | — | Default crop profile for a crop type |
Tool definitions are emitted by ToolRegistry.to_dict() / .to_json() and validated against assets/schemas/tool.schema.json by the test suite.
ToolRegistry.invoke(name, params, ctx, flags) enforces: unknown tool → {"status":"error"}; disabled feature flag → {"status":"disabled"}; retryable tools retry up to max_retries.
7. Hooks (lifecycle)
HookRegistry dispatches callables at well-defined phases. Built-in hooks (vfmc.agents.hooks.default_registry) provide baseline observability:
| Phase | Built-in hooks | |-------|----------------| | pre_run | audittrail | | pre_step | logging, tokenbudgetguard | | post_step | metrics, statesync, audittrail | | on_step_error | logging | | on_gate_failure | audittrail | | on_degradation | degradation (escalate + banner), audittrail | | post_run | metrics, audittrail | | on_finalize | statesync, audittrail |
Custom hooks register via registry.register("post_step", my_hook). Hook exceptions are caught and logged (never crash the run) unless they raise HookError (e.g. token-budget exhaustion → graceful degradation).
8. Router (chain-of-thought)
ChainOfThoughtRouter.plan(query) returns a RoutingDecision with:
skills: ordered list of skill names to runskipped: skills skipped (with reason inreasoning)reasoning: explicit, ordered reasoning traceshort_circuit: true for trivial lookups (e.g. "list zones")
The router:
- Detects trivial lookups and short-circuits (no analysis pipeline).
- Starts from the full 5-skill pipeline.
- Skips skills whose feature flag is disabled.
- Drops skills whose prerequisites were skipped.
- Guarantees
sub-core-analysisis present for any analysis query.
9. Configuration (src/vfmc/config/)
Type-safe, validated configuration with three priority layers:
- Environment variables (prefix
VFMC_, nested via__, e.g.
VFMC_FLAGS_WEB_SEARCH_ENABLED=false).
- Config file (
config/settings.yaml, path override viaVFMC_CONFIG). - Built-in defaults (
SystemDefaults).
from vfmc.config import get_config
cfg = get_config()
cfg.llm.server # LLMServer.SIMULATION
cfg.flags.web_search_enabled # True
cfg.agent.max_sub_agent_retries # 2
validate_config(config) enforces cross-field rules (token budget ordering, temperature range, degradation floor/ceiling, evidence minimums) and raises ValueError on any violation. Config schemas: assets/schemas/system-config.schema.json.
10. End-to-End Run
from vfmc.agents import run_harness
report = run_harness("analyze arctic lettuce 4 layers 10kw")
# report.verdict -> "Feasible & Efficient"
# report.universal_gates -> {"U1": True, ..., "U6": True}
# report.degradation_level -> 2 (offline web fallback)
# report.limitation_banner -> "LIMITATION NOTICE: ..."
# report.output -> structured analysis dict
CLI equivalent:
python scripts/run_harness.py "analyze arctic lettuce 4 layers 10kw" --pretty
# or via the installed entry point:
vfmc analyze --query "analyze arctic lettuce 4 layers 10kw"
11. Testing the Registry
python -m pytest tests/test_agents.py tests/test_config.py -q
The test suite exercises:
- Tool input validation (good + bad params)
- Hook firing across all phases
- Skill registry resolution + prerequisite validation
- Router planning (full pipeline, trivial short-circuit, flag-disabled skips)
- Orchestrator end-to-end with all universal gates passing
- Config loading from YAML + env overrides + validation errors
12. File Map
| Path | Purpose | |------|---------| | src/vfmc/agents/context.py | AgentContext, TokenBudget, LogEntry | | src/vfmc/agents/base.py | SkillBase, SkillResult, QualityGate | | src/vfmc/agents/hooks.py | HookRegistry + built-in hooks | | src/vfmc/agents/tools.py | Tool, ToolRegistry + built-in tools | | src/vfmc/agents/registry.py | SkillRegistry, default_registry | | src/vfmc/agents/router.py | ChainOfThoughtRouter, RoutingDecision | | src/vfmc/agents/orchestrator.py | Orchestrator, RunReport, `run_har
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dungnotnull
- Source: dungnotnull/vertical-farming-mobile-container-agent-skill
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.