Skip to content

Context

dotagents._context

Assemble the effective context an agent should see in a scope.

assemble_context(agent, scope, *, inline=False, expand_vars=True)

Assemble the effective context text (markdown) for the given agent in a :class:~dotagents._scope.Scope.

Returns '' if, after subtracting what the agent's harness already loads, there is nothing new to emit (no empty double of already-loaded content). inline=True appends the on-demand files the sources reference (see :func:_inline_referenced_files for why that is opt-in). expand_vars (default on) replaces $<NAME>_OVERLAY_ROOT with the overlay's directory, for a reader with no populated shell; pass False for text written into a file that may be committed (see :func:_expand_placeholders).

Source code in src/dotagents/_context.py
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
def assemble_context(
    agent: _agents.Agent, scope: _scope.Scope, *, inline: bool = False,
    expand_vars: bool = True,
) -> str:
    """Assemble the effective context text (markdown) for the given agent in a
    :class:`~dotagents._scope.Scope`.

    Returns '' if, after subtracting what the agent's harness already loads,
    there is nothing new to emit (no empty double of already-loaded content).
    ``inline=True`` appends the on-demand files the sources reference (see
    :func:`_inline_referenced_files` for why that is opt-in).
    ``expand_vars`` (default on) replaces ``$<NAME>_OVERLAY_ROOT`` with the
    overlay's directory, for a reader with no populated shell; pass ``False``
    for text written into a file that may be committed (see
    :func:`_expand_placeholders`)."""
    text, source_paths = _assemble(agent, scope, inline, expand_vars)
    if not source_paths:
        return ""
    text += _get_skills_listing(scope)
    text += _get_local_additions_listing(scope)
    if expand_vars:  # a machine path: never into a file that may be committed
        text += "\n\nPython for skills (`$AGENTS_PYTHON`): `%s`\n" % skills_python(scope)
    return text

assemble_context_data(agent, scope, *, inline=False, expand_vars=True)

Structured form of the assembled context, for --format json.

Shape

{ "agent": , "harness": , "sources": [, ...], # after harness subtraction "context": , "skills": [{"name": ..., "description": ..., "path": }, ...], "local_additions": [{"overlay_file": ..., "local": [, ...]}, ...], "python": , }

context is the same assembled(+inlined, with inline=True) text the markdown format emits, but WITHOUT the skills and local-additions listings appended -- both are their own structured fields so a consumer can render them separately.

Source code in src/dotagents/_context.py
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
def assemble_context_data(
    agent: _agents.Agent, scope: _scope.Scope, *, inline: bool = False,
    expand_vars: bool = True,
) -> "dict[str, object]":
    """Structured form of the assembled context, for ``--format json``.

    Shape:
        {
          "agent": <registry name>,
          "harness": <harness_id>,
          "sources": [<absolute source path>, ...],  # after harness subtraction
          "context": <assembled markdown text, minus the skills listing>,
          "skills": [{"name": ..., "description": ..., "path": <SKILL.md>}, ...],
          "local_additions": [{"overlay_file": ..., "local": [<path>, ...]}, ...],
          "python": <the interpreter skills run with, see skills_python>,
        }
    ``context`` is the same assembled(+inlined, with ``inline=True``) text the
    markdown format emits, but WITHOUT the skills and local-additions listings
    appended -- both are their own structured fields so a consumer can render
    them separately."""
    text, source_paths = _assemble(agent, scope, inline, expand_vars)

    skills = [
        {"name": n, "description": d, "path": str(p)} for n, d, p in _collect_skills(scope)
    ]

    return {
        "agent": agent.name,
        "harness": agent.harness_id or agent.name,
        "sources": source_paths,
        "context": text,
        "skills": skills,
        "local_additions": [
            {"overlay_file": str(path), "local": [str(p) for p in found]}
            for path, found in local_additions(scope)
        ],
        "python": skills_python(scope),
    }

local_additions(scope)

The user's own additions to installed overlay files: for each .md an overlay ships in a subdirectory (kb/, flows/, rules/ ... -- not skills/, whose published copies sit at the same path in a store), every store's file at the same relative path (~/.agents/kb/RUST.md for an overlay's kb/RUST.md), in store order. An overlay file is upstream's copy, replaced by overlays sync; the addition is where the user's own text lives. A store's root files (AGENTS.md, env.py) never match: only a file in a subdirectory counts.

Source code in src/dotagents/_context.py
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
def local_additions(scope: _scope.Scope) -> "list[tuple[Path, list[Path]]]":
    """The user's own additions to installed overlay files: for each ``.md``
    an overlay ships in a subdirectory (``kb/``, ``flows/``, ``rules/`` ... --
    not ``skills/``, whose published copies sit at the same path in a store),
    every store's file at the same relative path (``~/.agents/kb/RUST.md`` for
    an overlay's ``kb/RUST.md``), in store order. An overlay file is upstream's
    copy, replaced by ``overlays sync``; the addition is where the user's own
    text lives. A store's root files (``AGENTS.md``, ``env.py``) never match:
    only a file in a subdirectory counts."""
    stores = list(scope.stores)
    out: "list[tuple[Path, list[Path]]]" = []
    for overlay in scope.overlays:
        for path in overlay.files():
            rel = path.relative_to(overlay.path)
            if path.suffix.lower() != ".md" or len(rel.parts) < 2 or rel.parts[0] == "skills":
                continue
            found = [store / rel for store in stores if (store / rel).is_file()]
            if found:
                out.append((path, found))
    return out

skills_python(scope)

The interpreter skills run with: the scope venv's (dotagents._pyvenv), which imports duho, every overlay's requirements and every overlay lib; else the one running dotagents.

Source code in src/dotagents/_context.py
471
472
473
474
475
476
477
478
479
480
def skills_python(scope: _scope.Scope) -> str:
    """The interpreter skills run with: the scope venv's (`dotagents._pyvenv`),
    which imports duho, every overlay's requirements and every overlay lib;
    else the one running dotagents."""
    import sys

    from dotagents import _pyvenv

    venv = _pyvenv.active_venv(scope)
    return str(_pyvenv.venv_python(venv)) if venv is not None else sys.executable