CommunityCoding & Developmentgithub.com

bitsky-tech/AmphiLoop

Public agent skills based on Bridgic

Works with~Claude CodeCodex CLI~CursorAntigravity
npx add-skill bitsky-tech/AmphiLoop

name: bridgic-amphibious description: "Build agents with the Bridgic Amphibious dual-mode framework — combining LLM-driven (agent) and deterministic (workflow) execution with automatic fallback and human-in-the-loop support. Use when: (1) writing code that imports from bridgic.amphibious, (2) creating AmphibiousAutoma subclasses, (3) defining CognitiveWorker think units, (4) implementing on_agent/on_workflow methods, (5) working with CognitiveContext, Exposure system, or cognitive policies, (6) adding human-in-the-loop interactions (HumanCall, request_human, request_human_tool), (7) scaffolding a new amphibious project via CLI, (8) any task involving the bridgic-amphibious framework."

Bridgic Amphibious

Dual-mode agent framework: agents operate in LLM-driven (on_agent) and deterministic (on_workflow) modes with automatic fallback between them.

Dependencies

A bridgic-amphibious project requires the following packages:

PackageDescription
bridgic-coreCore framework (Worker, Automa, GraphAutoma, ASL)
bridgic-amphibiousDual-mode agent framework
bridgic-llms-openaiLLM provider (only required for AGENT / AMPHIFLOW modes)
python-dotenv.env file loading

Before using this package, you need to install the dependencies by using the provided install script:

bash "skills/bridgic-amphibious/scripts/install-deps.sh" "$PWD"

The script checks uv availability, initializes a uv project if needed, installs any missing packages via uv add, and runs uv sync to finalize the environment. When it exits successfully the project is fully initialized and ready to use — no manual uv add / uv sync follow-up is required.

LLM Setup

Amphibious agents accept a BaseLlm instance with astructure_output protocol from a bridgic LLM provider package. The LLM is required for AGENT and AMPHIFLOW modes; pure WORKFLOW mode can run without one.

from bridgic.llms.openai import OpenAILlm, OpenAIConfiguration

llm = OpenAILlm(
    api_key="your-api-key",
    api_base="https://api.openai.com/v1",  # or custom endpoint
    configuration=OpenAIConfiguration(model="gpt-4o", temperature=0.0),
)

Other providers with same protocol: bridgic.llms.vllm.VllmServerLlm (self-hosted vLLM).

Quick Start

from bridgic.amphibious import (
    AmphibiousAutoma, CognitiveContext, CognitiveWorker, think_unit,
)
from bridgic.core.agentic.tool_specs import FunctionToolSpec

async def get_weather(city: str) -> str:
    """Get weather for a city."""
    return f"Sunny, 22°C in {city}"

class WeatherAgent(AmphibiousAutoma[CognitiveContext]):
    planner = think_unit(
        CognitiveWorker.inline("Look up weather and provide a summary."),
        max_attempts=5,
    )
    async def on_agent(self, ctx: CognitiveContext):
        await self.planner

agent = WeatherAgent(llm=llm, verbose=True)
result = await agent.arun(
    goal="Check the weather in Tokyo and London.",
    tools=[FunctionToolSpec.from_raw(get_weather)],
)

Project Scaffolding

Use the CLI to bootstrap a new project:

bridgic-amphibious create -n my_project
bridgic-amphibious create -n my_project --task "Navigate to example.com and extract data"
bridgic-amphibious create -n my_project --base-dir /path/to/projects

Creates: task.md, config.py, tools.py, workers.py, agents.py, skills/, result/, log/.

Core Concepts

Agent = Think Units + Context Orchestration. Agents are defined by declaring CognitiveWorker think units and orchestrating them in on_agent() or on_workflow().

Four-layer architecture:

  1. Exposure — data visibility abstraction (LayeredExposure / EntireExposure)
  2. CognitiveContext — state container (goal, tools, skills, history)
  3. CognitiveWorker — pure thinking unit (observe-think-act)
  4. AmphibiousAutoma — orchestration engine (mode routing, lifecycle)

OTC Cycle: Observe -> Think -> Act, with hook points at each phase.

Four RunModes: AGENT (LLM-driven), WORKFLOW (deterministic), AMPHIFLOW (workflow + agent fallback), AUTO (auto-detect from overridden methods, default).

AUTO resolution: only on_agent overridden → AGENT; only on_workflow overridden → WORKFLOW; both overridden → AMPHIFLOW.

Key Patterns

Agent Mode — LLM decides

class MyAgent(AmphibiousAutoma[CognitiveContext]):
    worker = think_unit(CognitiveWorker.inline("Decide next step."), max_attempts=10)
    async def on_agent(self, ctx):
        await self.worker

Workflow Mode — Developer decides

from bridgic.amphibious import ActionCall

class MyWorkflow(AmphibiousAutoma[CognitiveContext]):
    async def on_workflow(self, ctx):
        result = yield ActionCall("tool_name", arg1="value")
        # result is List[ToolResult]

# Pure workflow mode does not need an LLM.
await MyWorkflow().arun(goal="...", tools=[...])

Amphiflow Mode — Workflow with agent fallback

from bridgic.amphibious import RunMode, AgentCall

class MyHybrid(AmphibiousAutoma[CognitiveContext]):
    fixer = think_unit(CognitiveWorker.inline("Fix the problem."), max_attempts=5)
    async def on_agent(self, ctx): await self.fixer
    async def on_workflow(self, ctx):
        yield ActionCall("fill_field", name="user", value="john")
        yield ActionCall("click_button", name="submit")

await MyHybrid(llm=llm).arun(
    goal="...", tools=[...],
    mode=RunMode.AMPHIFLOW, max_consecutive_fallbacks=2,
)

Human-in-the-Loop

from bridgic.amphibious import ActionCall, HumanCall

class MyAgent(AmphibiousAutoma[CognitiveContext]):
    worker = think_unit(CognitiveWorker.inline("Execute step."), max_attempts=10)

    async def on_agent(self, ctx):
        await self.worker
        feedback = await self.request_human("Proceed?")  # Entry 1: code-level

    async def on_workflow(self, ctx):
        yield ActionCall("do_something", arg="value")
        feedback = yield HumanCall(prompt="Confirm?")     # Entry 2: workflow yield

# Entry 3: LLM tool — `request_human` is auto-injected into every agent's
# tools, so the LLM can call it without you listing it in tools=[...].
# (Passing `request_human_tool` explicitly is harmless — it is deduped.)
await MyAgent(llm=llm).arun(goal="...", tools=[my_tool])

# If you want to be explicit, importing and passing `request_human_tool` still OK.
from bridgic.amphibious.builtin_tools import request_human_tool
await agent.arun(goal="...", tools=[request_human_tool, ...])  # also fine

Custom Pydantic Output

from pydantic import BaseModel

class Plan(BaseModel):
    phases: list[str]

class Planner(AmphibiousAutoma[CognitiveContext]):
    plan = think_unit(
        CognitiveWorker.inline("Create a plan.", output_schema=Plan),
        max_attempts=1,
    )
    async def on_agent(self, ctx):
        result = await self.plan  # Returns Plan instance

Phase Annotation (snapshot)

async def on_agent(self, ctx):
    async with self.snapshot(goal="Research phase"):
        await self.researcher
    async with self.snapshot(goal="Writing phase"):
        await self.writer

Reference Files

Related Skills