Skip to content

Config

pycodeloop.core.config.Config

Import

You can import the Config class with:

from pycodeloop import Config
from pycodeloop.providers import GenericProvider
Example

class pycodeloop.core.config.Config

config = Config(
    provider=GenericProvider.from_json("path/to/config.json"),
)

Parameters:

Name Type Description Default
provider Optional[Provider]

LLM backend driving the agent — always a GenericProvider under the hood. Defaults to the provider named by the PYCODELOOP_PROVIDER env var (a path to a JSON config file, a bare "generic" name, or a 'module.path:ClassName'; a bundled Anthropic config when unset).

None
tools Optional[List[Tool]]

Tools exposed to the agent. Defaults to the built-in read/write/edit/grep/bash set.

None
system_prompt Optional[str]

Overrides the default system prompt.

None
max_turns int

Hard cap on tool-use loop iterations.

MAX_TURNS
max_history_turns Optional[int]

Cap the session on the number of most recent user-initiated turns kept — older turns are dropped as a whole unit (never mid tool_calls/ tool_result) before each provider call. Defaults to 20; pass None to let the session grow without bound instead.

20
skills bool

Discover Claude Code skills/memory, Cursor rules, and AGENTS.md files on this machine and this project, expose them as a read_skill tool, and list them in the system prompt so the agent knows what's available.

False
skill_sources Optional[Set[str]]

Limit discovery to these sources ("claude-skill", "claude-memory", "cursor-rule", "agents-md"). Defaults to all of them.

None
skills_refresh bool

Skip the ~/.pycodeloop/config.json skills cache and force a full rescan.

False
storage Optional[Sessions]

Persists the session so CodeLoop.run(prompt, session_key=...) can resume a conversation across process restarts. Defaults to SqliteSessions() (~/.pycodeloop/pycodeloop.db). Pass False to keep sessions in memory only, for the life of the CodeLoop instance.

None

Attributes:

Name Type Description
provider Provider
tools List[Tool]
system_prompt Optional[str]
max_turns int
skills List[Skill]
storage Optional[Sessions]
Source code in pycodeloop/core/config.py
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
class Config:
    """
    Import:
        You can import the **Config** class with:

            from pycodeloop import Config
            from pycodeloop.providers import GenericProvider

    Example:
        `class` pycodeloop.core.config.Config

            config = Config(
                provider=GenericProvider.from_json("path/to/config.json"),
            )

    Args:
        provider (Optional[Provider]): LLM backend driving the agent —
            always a `GenericProvider` under the hood. Defaults to the
            provider named by the `PYCODELOOP_PROVIDER` env var (a
            path to a JSON config file, a bare `"generic"` name, or a
            `'module.path:ClassName'`; a bundled Anthropic config when
            unset).

        tools (Optional[List[Tool]]): Tools exposed to the agent.
            Defaults to the built-in read/write/edit/grep/bash set.

        system_prompt (Optional[str]): Overrides the default system
            prompt.

        max_turns (int): Hard cap on tool-use loop iterations.

        max_history_turns (Optional[int]): Cap the session on the
            number of most recent user-initiated turns kept — older
            turns are dropped as a whole unit (never mid tool_calls/
            tool_result) before each provider call. Defaults to `20`;
            pass `None` to let the session grow without bound instead.

        skills (bool): Discover Claude Code skills/memory, Cursor rules,
            and AGENTS.md files on this machine and this project, expose
            them as a `read_skill` tool, and list them in the system
            prompt so the agent knows what's available.

        skill_sources (Optional[Set[str]]): Limit discovery to these
            sources ("claude-skill", "claude-memory", "cursor-rule",
            "agents-md"). Defaults to all of them.

        skills_refresh (bool): Skip the `~/.pycodeloop/config.json` skills
            cache and force a full rescan.

        storage (Optional[Sessions]): Persists the session so
            `CodeLoop.run(prompt, session_key=...)` can resume a
            conversation across process restarts. Defaults to
            `SqliteSessions()` (`~/.pycodeloop/pycodeloop.db`). Pass `False`
            to keep sessions in memory only, for the life of the
            `CodeLoop` instance.

    Attributes:
        provider (Provider):
        tools (List[Tool]):
        system_prompt (Optional[str]):
        max_turns (int):
        skills (List[Skill]):
        storage (Optional[Sessions]):
    """

    _PROVIDERS = {"provider": Provider, "storage": Sessions}

    def __init__(
        self,
        provider: Provider | None = None,
        tools: list[Tool] | None = None,
        system_prompt: str | None = None,
        max_turns: int = Settings.MAX_TURNS,
        max_history_turns: int | None = 20,
        skills: bool = False,
        skill_sources: set[str] | None = None,
        skills_refresh: bool = False,
        storage: Sessions | bool | None = None,
    ) -> None:
        self.provider = provider if provider is not None else _default_provider()
        self.tools = list(tools) if tools is not None else list(DEFAULT_TOOLS)
        self.system_prompt = system_prompt
        self.max_turns = max_turns
        self.max_history_turns = max_history_turns
        self.skills = self._discover_skills(skills, skill_sources, skills_refresh)
        self.storage = None if storage is False else storage or _default_storage()

        self._validate()

    def _discover_skills(
        self, enabled: bool, sources: set[str] | None, refresh: bool
    ) -> list:
        if not enabled:
            return []

        found = discover_skills(sources=sources, use_cache=not refresh)

        if not found:
            return found

        self.tools = [*self.tools, ReadSkillTool(found)]
        base_prompt = (
            self.system_prompt
            if self.system_prompt is not None
            else DEFAULT_SYSTEM_PROMPT
        )
        self.system_prompt = f"{base_prompt}\n\n{render_skills_index(found)}"
        return found

    def _validate(self) -> None:
        for name, abc in self._PROVIDERS.items():
            value = getattr(self, name)

            if value is not None and not isinstance(value, abc):
                raise NotProviderInstance(name=name)

max_history_turns = max_history_turns instance-attribute

max_turns = max_turns instance-attribute

provider = provider if provider is not None else _default_provider() instance-attribute

skills = self._discover_skills(skills, skill_sources, skills_refresh) instance-attribute

storage = None if storage is False else storage or _default_storage() instance-attribute

system_prompt = system_prompt instance-attribute

tools = list(tools) if tools is not None else list(DEFAULT_TOOLS) instance-attribute

__init__(provider=None, tools=None, system_prompt=None, max_turns=Settings.MAX_TURNS, max_history_turns=20, skills=False, skill_sources=None, skills_refresh=False, storage=None)

Source code in pycodeloop/core/config.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def __init__(
    self,
    provider: Provider | None = None,
    tools: list[Tool] | None = None,
    system_prompt: str | None = None,
    max_turns: int = Settings.MAX_TURNS,
    max_history_turns: int | None = 20,
    skills: bool = False,
    skill_sources: set[str] | None = None,
    skills_refresh: bool = False,
    storage: Sessions | bool | None = None,
) -> None:
    self.provider = provider if provider is not None else _default_provider()
    self.tools = list(tools) if tools is not None else list(DEFAULT_TOOLS)
    self.system_prompt = system_prompt
    self.max_turns = max_turns
    self.max_history_turns = max_history_turns
    self.skills = self._discover_skills(skills, skill_sources, skills_refresh)
    self.storage = None if storage is False else storage or _default_storage()

    self._validate()