chane35's picture
PERMANENCE: reversibility-aware RL environment for training LLM agents
796da7c verified
|
Raw
History Blame
3.03 kB

How to add a new domain

PERMANENCE's framework is domain-agnostic. Adding a new domain (e.g. cloud ops, robotics, financial ops) is a matter of creating one new folder under permanence/domains/ and implementing four small pieces. You should not need to edit any file outside that folder.

Checklist

permanence/domains/<your_domain>/
β”œβ”€β”€ __init__.py        # `from . import register`  (4 lines)
β”œβ”€β”€ register.py        # calls core.register_domain(...)
β”œβ”€β”€ actions.py         # action definitions
β”œβ”€β”€ tasks.py           # task templates (TaskSpec + world_state_init_fn)
└── simulators/        # (optional) stateful sandboxes like fs.py/git.py/db.py

Then add your domain to the import list in permanence/domains/__init__.py:

from . import meridian  # noqa: F401
from . import devtools  # noqa: F401
from . import <your_domain>  # noqa: F401

That's it. import permanence will now register your domain and permanence.core.get_registry().summary() will list your actions + tasks.

What each file holds

__init__.py

"""<Your domain> β€” one-line description."""
from . import register  # noqa: F401

register.py

from ...core import register_domain
from .actions import ACTIONS        # dict[str, ActionDefinition]
from .tasks import TASK_TEMPLATES   # dict[str, TaskTemplate]

register_domain(
    name="<your_domain>",
    description="<one-line summary>",
    actions=ACTIONS,
    task_templates=TASK_TEMPLATES,
)

actions.py

Define ACTIONS: Dict[str, ActionDefinition]. Each action needs:

  • action_id β€” unique string (namespace with a prefix to avoid collisions)
  • r_level_fn(world_state, params) -> int β€” returns 1-5 based on world state
  • consequences β€” WorldStateMutation list (empty if domain owns mutations)

See permanence.domains.devtools.actions.ACTIONS for a working example.

tasks.py

Define TASK_TEMPLATES: Dict[str, TaskTemplate]. Each template bundles:

  • TaskSpec (task_id, narrative, max_steps, success_fn)
  • ScenarioGenerator (parameter ranges for randomization)
  • world_state_init_fn(sampled, scenario_id) -> WorldState

See permanence.domains.devtools.tasks.task_templates() for the DevTools pattern including per-episode randomization.

simulators/ (optional)

If your domain needs stateful sandboxes (like DevTools' fs/git/db), put them here. Attach simulator handles to WorldState via optional fields (see WorldState.fs, .git, .db). Keep simulators isolated: no subprocess, no network, no real disk writes. Unit tests must assert this.

Keep it clean

  • Never import from another domain. The whole point is independence.
  • Namespace your action ids. fs_rm, git_push, deploy_prod β€” not rm, push, deploy.
  • Ship unit tests. Isolation tests + reversibility gradient tests.
  • Add a curriculum entry. Update CurriculumScheduler to recognize your domain string ("devtools", "meridian", or your new one).