main
md 126 lines 8.81 KB
Rendered Raw
1 # projects.py DOX
2
3 ## Purpose
4
5 - Own the `projects.py` helper module.
6 - This module owns project metadata, workspace creation, Git status, and project-scoped settings including per-project MCP server config.
7 - Keep this file-level DOX profile synchronized with `projects.py` because this directory is intentionally flat.
8
9 ## Ownership
10
11 - `projects.py` owns the runtime implementation.
12 - `projects.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation.
13 - Classes:
14 - `FileStructureInjectionSettings` (`TypedDict`)
15 - `SubAgentSettings` (`TypedDict`)
16 - `BasicProjectData` (`TypedDict`)
17 - `GitStatusData` (`TypedDict`)
18 - `EditProjectData` (`BasicProjectData`)
19 - Top-level functions:
20 - `get_projects_parent_folder()`
21 - `get_project_folder(name: str)`
22 - `get_project_meta(name: str, *sub_dirs)`
23 - `validate_project_name(name: str | None) -> str`
24 - `delete_project(name: str)`
25 - `create_project(name: str, data: BasicProjectData)`
26 - `clone_git_project(name: str, git_url: str, git_token: str, data: BasicProjectData)`: Clone a git repository as a new A0 project. Token is used only for cloning via http header.
27 - `load_project_header(name: str)`
28 - `_default_file_structure_settings()`
29 - `_normalizeBasicData(data: BasicProjectData) -> BasicProjectData`
30 - `_normalizeEditData(data: EditProjectData) -> EditProjectData`
31 - `_edit_data_to_basic_data(data: EditProjectData)`
32 - `_basic_data_to_edit_data(data: BasicProjectData) -> EditProjectData`
33 - `update_project(name: str, data: EditProjectData)`
34 - `load_basic_project_data(name: str) -> BasicProjectData`
35 - `load_edit_project_data(name: str) -> EditProjectData`
36 - `save_project_header(name: str, data: BasicProjectData)`
37 - `load_project_extended_data(name: str) -> ProjectExtendedData`
38 - `save_project_extended_data(name: str, project_data: ProjectExtendedData)`
39 - `_project_extended_data_for_save(data: object) -> ProjectExtendedData`
40 - `_merge_project_extended_data(data: EditProjectData, extended_data: object) -> None`
41 - `load_project_mcp_servers(name: str) -> str`
42 - `save_project_mcp_servers(name: str, mcp_servers: str)`
43 - `get_active_projects_list()`
44 - `_get_projects_list(parent_dir)`
45 - `reconcile_agent_profile(context: AgentContext, project_name: str | None) -> bool`
46 - `reconcile_agent_profiles(project_name: str | None, *, all_scopes: bool=...) -> None`
47 - `activate_project(context_id: str, name: str, mark_dirty: bool=...)`
48 - `deactivate_project(context_id: str, mark_dirty: bool=...)`
49 - `reactivate_project_in_chats(name: str)`
50 - `deactivate_project_in_chats(name: str)`
51 - `build_system_prompt_vars(name: str)`
52 - `get_agents_md_chain(root: str, target: str) -> list[tuple[str, str]]`
53 - `build_agents_md_protocol(name: str, target: str | None=...) -> str`
54 - `get_additional_instructions_files(name: str)`
55 - `get_project_instruction_files(name: str, include_agents_md: bool=...) -> list[tuple[str, str]]`
56 - `get_project_agents_md_instruction_file(name: str) -> tuple[str, str] | None`
57 - `_format_project_instruction_files(instruction_files: list[tuple[str, str]]) -> str`
58 - `_normalize_include_agents_md(value: object) -> bool`
59 - `load_project_subagents(name: str) -> dict[str, SubAgentSettings]`
60 - `save_project_subagents(name: str, subagents_data: dict[str, SubAgentSettings])`
61 - `set_project_subagent_enabled(name: str, profile_id: str, enabled: bool) -> None`
62 - `_normalize_subagents(subagents_data: dict[str, SubAgentSettings], project_name: str=...) -> dict[str, SubAgentSettings]`
63 - Notable constants/configuration names: `PROJECTS_PARENT_DIR`, `PROJECT_META_DIR`, `PROJECT_INSTRUCTIONS_DIR`, `PROJECT_KNOWLEDGE_DIR`, `PROJECT_SKILLS_DIR`, `PROJECT_HEADER_FILE`, `PROJECT_MCP_SERVERS_FILE`, `PROJECT_AGENTS_MD_FILES`, `DEFAULT_MCP_SERVERS_CONFIG`, `CONTEXT_DATA_KEY_PROJECT`.
64
65 ## Runtime Contracts
66
67 - Helper modules own reusable framework APIs and must preserve public callers unless all callers, tests, and docs are updated together.
68 - Update this file whenever public functions, classes, persistence behavior, path/security assumptions, side effects, or cross-module contracts change.
69 - Per-project MCP server configuration is persisted as `.a0proj/mcp_servers.json`, exposed through `load_edit_project_data(...)`, and saved during project create/clone/update flows.
70 - Additional project-edit payload sections are delegated through extensible `load_project_extended_data(...)` and `save_project_extended_data(...)`; the project helper must stay storage-agnostic and plugin-specific config rules belong to the owning plugin.
71 - Project extension data may add named top-level sections such as `llm`, but it must not overwrite core project fields owned by `EditProjectData`.
72 - Project extension save payloads exclude core project fields and transient inputs such as `git_token`; plugins needing core metadata should load it by project name.
73 - Project metadata setup creates and repairs `.a0proj/instructions`, `.a0proj/knowledge`, and `.a0proj/skills` so settings surfaces can open those folders consistently.
74 - AGENTS.md discovery is a linear root-to-target chain walk with `AGENTS.override.md` precedence; sibling directories are not scanned.
75 - Active-project AGENTS.md protocol guidance excludes the exact project root AGENTS.md because `build_system_prompt_vars(...)` already loads it into project instructions; prose for that protocol block lives in `prompts/agent.protocol.projects.agents_md.md`.
76 - Project MCP config uses the same JSON string shape as global MCP settings: an object with `mcpServers`.
77 - Project MCP load/save paths validate project names as simple folder basenames before touching `.a0proj/mcp_servers.json`.
78 - Activating or deactivating a project preserves the active chat profile when it
79 is available in the destination scope; otherwise it replaces it with the
80 configured default profile, then `agent0`, then the first available profile.
81 - Per-project profile availability is persisted sparsely in `.a0proj/agents.json`;
82 entries matching the profile definition's scoped default are omitted. The
83 helper retains the established tolerant load contract for read-only settings.
84 Profile-scoped mutations re-read the file strictly, preserve unrelated
85 entries, refuse malformed data, and write through `helpers.files`. General
86 project edit payloads neither expose nor mutate profile availability; legacy
87 `subagents` input is ignored.
88 - Profile reconciliation treats `None` as the Global scope. Callers must pass
89 `all_scopes=True` to check every loaded chat after a Global availability
90 change. Each pass resolves the available profile catalog once per encountered
91 scope; only chats whose active profile actually changes are persisted and
92 marked dirty. Context creation uses the same reconciliation after resolving
93 its scope, so a disabled configured profile cannot become invisibly active.
94 - Project updates and deletion refresh only chats assigned to that project and
95 persist each affected chat once; unrelated chats are never rewritten.
96 - Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion, plugin state, settings/state persistence, secret handling.
97 - Imported dependency areas include: `helpers`, `helpers.print_style`, `os`,
98 `typing`.
99
100 ## Key Concepts
101
102 - Important called helpers/classes observed in the source: `files.get_abs_path`, `files.delete_dir`, `deactivate_project_in_chats`, `files.create_dir_safe`, `create_project_meta_folders`, `_normalizeBasicData`, `save_project_header`, `save_project_mcp_servers`, `load_project_mcp_servers`, `save_project_extended_data`, `load_project_extended_data`, `_project_extended_data_for_save`, `_merge_project_extended_data`, `_PROJECT_CORE_EDIT_KEYS`, `_PROJECT_TRANSIENT_INPUT_KEYS`, `extension.extensible`, `files.basename`, `dirty_json.parse`, `FileStructureInjectionSettings`, `cast`, `_normalizeEditData`, `load_edit_project_data`, `_edit_data_to_basic_data`, `save_project_variables`, `save_project_secrets`, `save_project_subagents`, `reactivate_project_in_chats`, `load_basic_project_data`.
103 - Keep request/response, tool, or helper semantics documented here at the same time as source changes.
104
105 ## Work Guidance
106
107 - Preserve public helper APIs used by core code and plugins unless every caller is updated.
108 - Keep path, auth, secret, persistence, network, and subprocess behavior explicit and bounded.
109 - Prefer adding cohesive helper functions here only when behavior is reused across modules.
110
111 ## Verification
112
113 - Run targeted tests for changed helper behavior; run security regressions for auth, filesystem, WebSocket, tunnel, upload, or secret-handling helpers.
114 - Related tests observed by source search:
115 - `tests/test_model_config_project_presets.py`
116 - `tests/test_office_document_store.py`
117 - `tests/test_plugin_activation_ui.py`
118 - `tests/test_projects.py`
119 - `tests/test_skills_runtime.py`
120 - `tests/test_task_scheduler_timezone.py`
121 - `tests/test_time_travel.py`
122 - `tests/test_tool_action_contracts.py`
123
124 ## Child DOX Index
125
126 No child DOX files.