Multi-Agent Harness for Visual Design

yelboudouri1 pts0 comments

GitHub - EightPotions/Myli: Multi-Agent Harness for Visual Design · GitHub

/" data-turbo-transient="true" />

Skip to content

Search/

Sign in<br>Sign upAppearance settings

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

Uh oh!

There was an error while loading. Please reload this page.

EightPotions

Myli

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

main

BranchesTags

Go to file

CodeOpen more actions menu

Latest commit

History<br>7 Commits<br>7 Commits

Folders and files<br>NameNameLast commit message<br>Last commit date<br>.github/workflows

.github/workflows

docs

docs

src/myli

src/myli

tests

tests

.gitignore

.gitignore

.readthedocs.yaml

.readthedocs.yaml

LICENSE

LICENSE

README.md

README.md

pyproject.toml

pyproject.toml

uv.lock

uv.lock

View all files

Repository files navigation

Myli

Myli is a provider-neutral, pre-alpha Python harness for agents that propose<br>RFC 6902 changes to application-owned JSON design documents. It never persists<br>or applies the returned candidate to application state.

The core is independent of Pydantic, canvas formats, rendering stacks, model<br>providers, ORMs, progress transports, and persistence systems.

Read the Myli documentation for the<br>complete guide and API reference.

Run contract

result = await myli.run(<br>request=user_request,<br>design=current_design,<br>can_edit=True,<br>capabilities={"media.transform"},<br>history=history,<br>on_event=handle_event,<br>on_step=persist_step,

RunResult contains the user-facing message, optional validated candidate,<br>changed flag, proposed patch, approved run-scoped assets, all tool outcomes,<br>step traces, run ID, and final provider metadata. Successful and unsuccessful<br>tool outcomes are also available as filtered properties.

Generic documents and injected models

dict[str, Any]:<br>if not isinstance(value, dict):<br>raise ValueError("document must be an object")<br>return value

design_spec = DesignSpec(<br>name="design",<br>schema={"type": "object"},<br>validator=load_untrusted_document,<br>serializer=lambda document: document,<br>normalizer=normalize_trusted_stored_document,<br>input_migrator=migrate_stored_document,

class ApplicationMainModel:<br>async def complete(self, request: ModelRequest) -> ModelResponse:<br>return await application_transport.complete(request)

myli = Myli(<br>design_spec=design_spec,<br>main_model=ApplicationMainModel(),<br>vision_model=application_vision_model,<br>renderer=application_renderer,<br>)">from typing import Any

from myli import DesignSpec, ModelRequest, ModelResponse, Myli

def load_untrusted_document(value: Any) -> dict[str, Any]:<br>if not isinstance(value, dict):<br>raise ValueError("document must be an object")<br>return value

design_spec = DesignSpec(<br>name="design",<br>schema={"type": "object"},<br>validator=load_untrusted_document,<br>serializer=lambda document: document,<br>normalizer=normalize_trusted_stored_document,<br>input_migrator=migrate_stored_document,

class ApplicationMainModel:<br>async def complete(self, request: ModelRequest) -> ModelResponse:<br>return await application_transport.complete(request)

myli = Myli(<br>design_spec=design_spec,<br>main_model=ApplicationMainModel(),<br>vision_model=application_vision_model,<br>renderer=application_renderer,

DesignSpec has deliberately separate methods for trusted stored input and<br>untrusted model candidates. Candidate JSON is validated at runtime against the<br>schema and must serialize back without coercion, default insertion, field<br>dropping, or any other silent rewrite. Stored input may opt into migration and<br>normalization before each run.

MainModel and VisionModel are public protocols. Applications may inject<br>different transports, endpoints, credentials, or fakes. LiteLLMMainModel and<br>LiteLLMVisionModel are optional implementations:

python -m pip install "myli[litellm]"

The LiteLLM main implementation supports structured, JSON, and text output<br>modes, rejects options that override client-owned request fields, and translates<br>provider failures into Myli's stable exception hierarchy.

Pydantic remains optional:

from myli.integrations.pydantic import PydanticDesignSpec

Tools, policies, and middleware

AgentTool is domain-neutral. A tool declares a JSON input schema, capabilities,<br>per-run call budget, timeout, and result-size limit, then receives a ToolContext<br>with the current run ID, isolated evidence, zero-based model step, run-unique<br>step and tool-batch IDs, and its zero-based position and size within that batch:

async def execute(arguments, context):<br>...

Myli validates arguments and results, enforces capabilities and limits, and<br>records a ToolOutcome with one of succeeded, failed, rejected, timed_out, or<br>deferred. Calls are sequential by default. Parallel execution requires both the<br>harness option and an explicit parallel_safe declaration on every call in the<br>batch. Each...

myli design request document design_spec complete

Related Articles