Workspace Manager¶
Workspace Manager — mvp.workspace_manager
Cluster: Core Infrastructure | Type: component | MCP Tools: 93
Overview¶
Isolated sandbox workspace manager that creates per-task temporary directories with optional git initialisation and enforces write-boundary checks so no component can escape its designated root. Returns a WorkspaceContext handle with a check_write_allowed() method that any file-writing component can call before touching the filesystem. Extended MCP blocks integrate Obsidian vault sync, always-on memory, and a Claude-style todo list.
When to use:
- Giving a code-execution or meta-programming agent a safe, ephemeral scratch area with git history
- Enforcing sandbox boundaries in multi-agent pipelines where components share a host filesystem
- Managing per-session persistent memory and todo lists via the Obsidian MCP integration
Obsidian and memory caveats
Core workspace creation, git initialisation, sandbox checks, note CRUD, search, daily notes, bookmarks, tasks, and vault templates work through local filesystem fallbacks. Operations that automate the Obsidian desktop app itself still require a working Obsidian CLI/binary and return clear OBSIDIAN_CLI_ERROR messages when it is unavailable.
Always-on memory can ingest text without an LLM by storing a basic fallback summary. Consolidation and natural-language querying depend on the configured memory model path (MEMORY_LLM_MODEL, with optional MEMORY_LLM_FALLBACK) and will report model failures instead of silently pretending to reason over memory.
Primary MCP risk-gate surface
workspace_manager_mcp exposes assess_operation, cleanup_workspace, restore_workspace, backup_workspace, workspace_health, list_workspaces, workspace_status, and list_patterns. Destructive cleanup/restore return review_required without mutation unless confirmed=True; health is read-only; backup remains path/id validated. Canonical envelopes use only verified, qualified-draft, or blocked-escalated in completion_state.
Example:
from mvp.workspace_manager import WorkspaceManagerBlock, WorkspaceRequest
block = WorkspaceManagerBlock(name="workspace_manager")
result = block.infer(WorkspaceRequest(workspace_id="task-42", init_git=True))
ctx = result.value
print(ctx.root_path) # /tmp/g6/task-42
print(ctx.check_write_allowed("/tmp/g6/task-42/out.py")) # True
print(ctx.check_write_allowed("/etc/passwd")) # False
Works well with: meta_programming, database, component_creator
Public API¶
WorkspaceManagerDecisionError(ValueError)¶
The LLM did not produce a usable, validated workspace-risk decision.
WorkspaceRiskDecision¶
Validated risk verdict for a requested workspace operation.
| Field | Type | Default |
|---|---|---|
op_kind | str | required |
allowed | bool | required |
op_risk | str | required |
baseline_risk | str | required |
requires_review | bool | False |
requires_human_review | bool | False |
has_git | bool | False |
degraded | bool | False |
llm_used | bool | False |
rationale | str | '' |
raw_response | str | '' |
WorkspaceManagerPlanner¶
Runtime-first facade with deterministic fallback + one-way risk clamp.
Constructor:
| Parameter | Type | Default |
|---|---|---|
runtime | WorkspaceRuntime \| None | None |
Methods:
decide(ctx: dict[str, Any]) -> WorkspaceRiskDecision¶
WorkspaceManagerPatternRuntime¶
Stateless executable mechanisms for workspace_manager's applied patterns.
Methods:
tighten(op_kind: str, op_risk: str, baseline_risk: str, allowed: bool = True, has_git: bool = False, requires_review: bool = False, requires_human_review: bool = False, degraded: bool = False) -> WorkspaceManagerPatternReview¶
One-way workspace-risk guard (hook-based-safety-guard-rails).
WorkspaceRequest(BaseModel)¶
Request to create or open an isolated workspace.
| Field | Type | Default |
|---|---|---|
workspace_id | str | required |
init_git | bool | True |
base_dir | str | '' |
WorkspaceContext(BaseModel)¶
Handle to an active isolated workspace.
| Field | Type | Default |
|---|---|---|
workspace_id | str | required |
root_path | Path | required |
git_initialised | bool | required |
degraded | bool | False |
degradation_reason | str | '' |
completion_state | CompletionState | 'qualified-draft' |
warning_card | dict | Field(default_factory=dict) |
evidence | dict | Field(default_factory=dict) |
request_id | str | '' |
task_id | str | '' |
run_id | str | '' |
Methods:
check_write_allowed(path: str | Path) -> bool¶
Return True iff path is inside root_path.
WorkspaceManagerSkillCatalog¶
Maps each applied pattern slug to a workspace-risk skill record.
Methods:
list_skills() -> list[WorkspaceManagerSkill]¶
executable_skills() -> list[WorkspaceManagerSkill]¶
get(slug: str) -> WorkspaceManagerSkill | None¶
WorkspaceManagerBlock(AIBlock[WorkspaceRequest, WorkspaceContext, None])¶
Creates an isolated per-solution workspace (directory + optional git repo).
| Field | Type | Default |
|---|---|---|
name | str | 'workspace_manager' |
base_dir | str | '' |
max_workspace_size_mb | int | 500 |
resource_bounds | ResourceBounds \| None | None |
usage | ResourceUsage | field(default_factory=ResourceUsage) |
Methods:
infer(data: WorkspaceRequest) -> Result[WorkspaceContext]¶
list_workspaces(base_dir: str = '') -> Result[list[dict]]¶
Return metadata for all managed workspaces under the configured root.
workspace_status(workspace_id: str, base_dir: str = '') -> Result[dict]¶
Return status metadata for one managed workspace.
cleanup_workspace(workspace_id: str, base_dir: str = '') -> Result[dict]¶
Delete one managed workspace after validating it remains under the workspace root.
backup_workspace(workspace_id: str, backup_dir: str = '', base_dir: str = '') -> Result[dict]¶
Create a tarball backup of a workspace.
restore_workspace(backup_path: str, workspace_id: str = '', base_dir: str = '') -> Result[dict]¶
Restore a workspace from a tarball backup.
safe_cleanup_workspace(workspace_id: str, base_dir: str = '', has_git: bool = False, confirmed: bool = False) -> Result[dict]¶
Review-gated cleanup_workspace (additive; wraps the unchanged primitive).
safe_restore_workspace(backup_path: str, workspace_id: str = '', base_dir: str = '', has_git: bool = False, confirmed: bool = False) -> Result[dict]¶
Review-gated restore_workspace (additive; wraps the unchanged primitive).
ObsidianWorkspaceMCPBlock(AIBlock[MCPObsidianInput, MCPObsidianOutput, dict])¶
83-op MCP block for Obsidian vault workspace management.
| Field | Type | Default |
|---|---|---|
name | str | 'obsidian_workspace_mcp' |
state | dict \| None | None |
vault_path | str | '' |
db_path | str | '' |
Methods:
infer(data: MCPObsidianInput) -> Result[MCPObsidianOutput]¶
MCPObsidianInput(BaseModel)¶
| Field | Type | Default |
|---|---|---|
op | OBSIDIAN_WORKSPACE_OPS | required |
run_id | str | '' |
node_id | str | '' |
path | str | '' |
content | str | '' |
template | str | '' |
property_name | str | '' |
property_value | str | '' |
query | str | '' |
tag_name | str | '' |
task_json | str | '' |
approved | bool \| None | None |
reasoning | str | '' |
goal | str | '' |
resource_bounds_json | str | '' |
event_type | str | '' |
detail | str | '' |
metric_key | str | '' |
filter_expr | str | '' |
format | str | 'text' |
source_path | str | '' |
dest_path | str | '' |
new_name | str | '' |
line_number | int | 0 |
status_filter | str | 'all' |
limit | int | 0 |
plugin_id | str | '' |
theme_name | str | '' |
workspace_name | str | '' |
css_name | str | '' |
base_name | str | '' |
base_schema | str | '' |
base_data | str | '' |
base_filter | str | '' |
record_id | str | '' |
code | str | '' |
selector | str | '' |
version | str | '' |
bookmark_path | str | '' |
memory_text | str | '' |
memory_source | str | '' |
memory_question | str | '' |
memory_id | int | 0 |
MCPObsidianOutput(BaseModel)¶
| Field | Type | Default |
|---|---|---|
success | bool | required |
op | str | required |
result | str | '' |
error | str | '' |
vault_path | str | '' |
items | list[str] | Field(default_factory=list) |
count | int | 0 |
properties | dict[str, str] | Field(default_factory=dict) |
degraded | bool | False |
degradation_reason | str \| None | None |
error_type | str | '' |
dep_name | str | '' |
retryable | bool | False |
next_action | str | '' |
WorkspaceManagerMCPBlock(AIBlock[WorkspaceManagerMCPInput, WorkspaceManagerMCPOutput, dict])¶
Dispatcher for 8 ops (producible operations, + ops/help meta).
Constructor:
| Parameter | Type | Default |
|---|---|---|
name | str | 'workspace_manager_mcp' |
state | dict \| None | None |
Methods:
infer(data: WorkspaceManagerMCPInput) -> Result[WorkspaceManagerMCPOutput]¶
Functions¶
summarize_workspace_manager_agentic_evidence(decisions: list[dict[str, Any]]) -> dict[str, Any]¶
Summarise runtime-vs-fallback workspace decisions with path redaction.
agentic_planner_enabled(default_enabled: bool = True) -> bool¶
Decide whether the agentic workspace-risk planner should be used.
deterministic_workspace_decision(ctx: dict[str, Any], block: Any | None = None) -> WorkspaceRiskDecision¶
The FIXED, HARD deterministic floor for a requested workspace operation.
apply_workspace_floor(baseline: WorkspaceRiskDecision, candidate: WorkspaceRiskDecision) -> WorkspaceRiskDecision¶
One-way action-tier risk clamp (output-verification-loop).
grounded_workspace_operation(ctx: dict[str, Any], planner: 'WorkspaceManagerPlanner | None' = None, block: Any | None = None) -> tuple[WorkspaceRiskDecision, Any, bool, str]¶
The ONE shared grounded chokepoint for EVERY workspace-risk decision.
applied_agentic_patterns() -> list[dict[str, Any]]¶
Return compact metadata for workspace_manager-applied vendored patterns.
check_write_allowed(root: Path, target: str | Path) -> Result[Path]¶
Validate that target lies within root.
get_skill_catalog() -> WorkspaceManagerSkillCatalog¶
MCP Tools¶
| Operation | Source |
|---|---|
init_vault | obsidian_workspace_mcp |
vault_health | obsidian_workspace_mcp |
create_run | obsidian_workspace_mcp |
get_run_status | obsidian_workspace_mcp |
list_runs | obsidian_workspace_mcp |
delete_run | obsidian_workspace_mcp |
create_branch | obsidian_workspace_mcp |
get_branch | obsidian_workspace_mcp |
list_branches | obsidian_workspace_mcp |
update_branch | obsidian_workspace_mcp |
emit_hitl | obsidian_workspace_mcp |
poll_hitl | obsidian_workspace_mcp |
list_decisions | obsidian_workspace_mcp |
append_trace | obsidian_workspace_mcp |
read_note | obsidian_workspace_mcp |
set_property | obsidian_workspace_mcp |
search_workspace | obsidian_workspace_mcp |
search_tags | obsidian_workspace_mcp |
get_backlinks | obsidian_workspace_mcp |
get_links | obsidian_workspace_mcp |
check_orphans | obsidian_workspace_mcp |
query_base | obsidian_workspace_mcp |
daily_log | obsidian_workspace_mcp |
get_metrics | obsidian_workspace_mcp |
sync_knowledge | obsidian_workspace_mcp |
create_note | obsidian_workspace_mcp |
append_note | obsidian_workspace_mcp |
prepend_note | obsidian_workspace_mcp |
move_note | obsidian_workspace_mcp |
rename_note | obsidian_workspace_mcp |
delete_note | obsidian_workspace_mcp |
list_notes | obsidian_workspace_mcp |
daily_read | obsidian_workspace_mcp |
daily_prepend | obsidian_workspace_mcp |
daily_path | obsidian_workspace_mcp |
read_property | obsidian_workspace_mcp |
remove_property | obsidian_workspace_mcp |
tag_count | obsidian_workspace_mcp |
tag_list | obsidian_workspace_mcp |
task_query | obsidian_workspace_mcp |
task_toggle | obsidian_workspace_mcp |
task_count | obsidian_workspace_mcp |
broken_links | obsidian_workspace_mcp |
bookmark_add | obsidian_workspace_mcp |
bookmark_remove | obsidian_workspace_mcp |
bookmark_list | obsidian_workspace_mcp |
bookmark_toggle | obsidian_workspace_mcp |
vault_info | obsidian_workspace_mcp |
vault_stats | obsidian_workspace_mcp |
workspace_list | obsidian_workspace_mcp |
workspace_load | obsidian_workspace_mcp |
workspace_save | obsidian_workspace_mcp |
workspace_delete | obsidian_workspace_mcp |
plugin_list | obsidian_workspace_mcp |
plugin_install | obsidian_workspace_mcp |
plugin_enable | obsidian_workspace_mcp |
plugin_disable | obsidian_workspace_mcp |
theme_list | obsidian_workspace_mcp |
theme_set | obsidian_workspace_mcp |
sync_start | obsidian_workspace_mcp |
sync_status | obsidian_workspace_mcp |
css_list | obsidian_workspace_mcp |
css_toggle | obsidian_workspace_mcp |
base_create | obsidian_workspace_mcp |
base_list | obsidian_workspace_mcp |
base_query | obsidian_workspace_mcp |
base_insert | obsidian_workspace_mcp |
base_update | obsidian_workspace_mcp |
base_delete | obsidian_workspace_mcp |
eval_js | obsidian_workspace_mcp |
vault_screenshot | obsidian_workspace_mcp |
dom_inspect | obsidian_workspace_mcp |
file_history | obsidian_workspace_mcp |
file_recover | obsidian_workspace_mcp |
file_versions | obsidian_workspace_mcp |
memory_ingest | obsidian_workspace_mcp |
memory_consolidate | obsidian_workspace_mcp |
memory_query | obsidian_workspace_mcp |
memory_stats | obsidian_workspace_mcp |
memory_delete | obsidian_workspace_mcp |
memory_clear | obsidian_workspace_mcp |
create_vault_from_template | obsidian_workspace_mcp |
list_vault_templates | obsidian_workspace_mcp |
ops | workspace_manager_mcp |
help | workspace_manager_mcp |
assess_operation | workspace_manager_mcp |
cleanup_workspace | workspace_manager_mcp |
restore_workspace | workspace_manager_mcp |
backup_workspace | workspace_manager_mcp |
workspace_health | workspace_manager_mcp |
list_workspaces | workspace_manager_mcp |
workspace_status | workspace_manager_mcp |
list_patterns | workspace_manager_mcp |