src.core.workspace module#

Workspace isolation and security management for autonomous agents.

This module ensures that client agents only operate within their designated project directories and cannot access the Marcus installation or system files.

The WorkspaceManager provides: - Automatic detection of Marcus installation directory - Configuration-based workspace assignment - Path validation and security enforcement - Audit logging of security violations

Examples

>>> manager = WorkspaceManager()
>>> workspace = manager.assign_agent_workspace("agent-001", "/home/user/project")
>>> manager.validate_path("/home/user/project/src/file.py")  # OK
>>> manager.validate_path("/usr/lib/python3/site-packages")  # Raises SecurityError
exception src.core.workspace.WorkspaceSecurityError[source]#

Bases: Exception

Raised when a security violation is detected.

This exception indicates an agent attempted to access a forbidden path.

Examples

>>> raise WorkspaceSecurityError("Access denied to system directory")
class src.core.workspace.WorkspaceConfig[source]#

Bases: object

Configuration for a single agent workspace.

Parameters:
  • workspace_id (str) – Unique identifier for the workspace

  • path (str) – Filesystem path to the workspace directory

  • agent_id (Optional[str]) – ID of the agent assigned to this workspace

  • is_readonly (bool) – Whether the workspace is read-only

Notes

Paths are automatically expanded and converted to absolute paths during initialization.

workspace_id: str#
path: str#
agent_id: str | None = None#
is_readonly: bool = False#
__post_init__()[source]#

Expand and validate the workspace path.

Converts relative paths to absolute and expands user home directory.

Return type:

None

__init__(workspace_id, path, agent_id=None, is_readonly=False)#
Parameters:
  • workspace_id (str)

  • path (str)

  • agent_id (str | None)

  • is_readonly (bool)

Return type:

None

class src.core.workspace.ProjectWorkspaces[source]#

Bases: object

Configuration for all project workspaces.

Parameters:
  • main_workspace (str) – Primary project workspace path

  • agent_workspaces (Dict[str, str]) – Mapping of agent IDs to their dedicated workspace paths

Examples

>>> config = ProjectWorkspaces(
...     main_workspace="/home/user/project",
...     agent_workspaces={"agent-001": "/home/user/project/agent1"}
... )
main_workspace: str#
agent_workspaces: Dict[str, str]#
__post_init__()[source]#

Expand all workspace paths to absolute paths.

Return type:

None

__init__(main_workspace, agent_workspaces=<factory>)#
Parameters:
Return type:

None

class src.core.workspace.WorkspaceManager[source]#

Bases: object

Manages workspace isolation and security boundaries for Marcus.

This class enforces security by maintaining a list of forbidden paths (including the Marcus installation) and validating all agent workspace assignments against these restrictions.

marcus_root#

Automatically detected Marcus installation directory

Type:

str

forbidden_paths#

Set of paths that agents are not allowed to access

Type:

Set[str]

agent_workspaces#

Mapping of agent IDs to their workspace configurations

Type:

Dict[str, WorkspaceConfig]

project_config#

Project-level workspace configuration

Type:

Optional[ProjectWorkspaces]

Examples

>>> manager = WorkspaceManager()
>>> workspace = manager.assign_agent_workspace("agent-001")
>>> print(workspace.path)  # /home/user/project
>>> manager.validate_path("/etc/passwd")  # Raises WorkspaceSecurityError

Notes

The Marcus installation directory is automatically detected and added to the forbidden paths list to prevent agents from modifying Marcus itself.

__init__(config_path=None)[source]#

Initialize WorkspaceManager with automatic Marcus detection.

Parameters:

config_path (Optional[str]) – Path to configuration file. If not provided, searches default locations.

Return type:

None

marcus_root: str#
forbidden_paths: Set[str]#
agent_workspaces: Dict[str, WorkspaceConfig]#
project_config: ProjectWorkspaces | None#
load_config(config_path)[source]#

Load workspace configuration from file.

Parameters:

config_path (str) – Path to JSON configuration file

Raises:
Return type:

None

Notes

Configuration format:

{
    "project": {
        "workspaces": {
            "main": "/path/to/project",
            "agents": {
                "agent-001": "/path/to/agent1/workspace"
            }
        }
    },
    "security": {
        "additional_forbidden_paths": ["/sensitive/data"]
    }
}
assign_agent_workspace(agent_id, workspace_path=None)[source]#

Assign a workspace to an agent.

Parameters:
  • agent_id (str) – Unique identifier for the agent

  • workspace_path (Optional[str]) – Explicit workspace path. If not provided, uses project configuration.

Returns:

The assigned workspace configuration

Return type:

WorkspaceConfig

Raises:

Examples

>>> workspace = manager.assign_agent_workspace(
...     "agent-001", "/home/user/project"
... )
>>> print(workspace.workspace_id)  # "agent-001_workspace"

Notes

If workspace_path is not provided, the method tries: 1. Pre-configured workspace for the specific agent 2. The main project workspace as fallback

get_agent_workspace(agent_id)[source]#

Get the assigned workspace for an agent.

Parameters:

agent_id (str) – The agent’s unique identifier

Returns:

The workspace configuration if assigned, None otherwise

Return type:

Optional[WorkspaceConfig]

validate_path(path)[source]#

Validate that a path is allowed (not in forbidden paths).

Parameters:

path (str) – Path to validate (can be relative or contain ~)

Returns:

The absolute path if valid

Return type:

str

Raises:

WorkspaceSecurityError – If the path is within a forbidden directory

Examples

>>> manager.validate_path("/home/user/project/file.py")  # OK
>>> manager.validate_path("~/project/file.py")  # Expands and validates
>>> manager.validate_path("/usr/lib/python3/os.py")  # Raises error
is_path_allowed(path)[source]#

Check if a path is allowed without raising an exception.

Parameters:

path (str) – Path to check

Returns:

True if path is allowed, False if forbidden

Return type:

bool

Examples

>>> if manager.is_path_allowed("/home/user/file.py"):
...     print("Path is safe to access")
add_forbidden_path(path)[source]#

Add a path to the forbidden list.

Parameters:

path (str) – Path to mark as forbidden

Return type:

None

Examples

>>> manager.add_forbidden_path("/sensitive/data")
>>> manager.is_path_allowed("/sensitive/data/file.txt")  # False
get_forbidden_paths()[source]#

Get list of all forbidden paths.

Returns:

Sorted list of forbidden paths

Return type:

List[str]

get_task_assignment_data(agent_id)[source]#

Get workspace data to include in task assignments.

This data should be sent to agents so they know where to work and what paths to avoid.

Parameters:

agent_id (str) – The agent’s identifier

Returns:

Dictionary containing: - workspace_path: Where the agent should work - workspace_id: Unique workspace identifier - forbidden_paths: List of paths to avoid - is_readonly: Whether the workspace is read-only

Return type:

Dict[str, Any]

Examples

>>> data = manager.get_task_assignment_data("agent-001")
>>> print(data['workspace_path'])  # /home/user/project
>>> print(len(data['forbidden_paths']))  # Number of forbidden paths
log_security_violation(agent_id, attempted_path, operation)[source]#

Log a security violation attempt.

Parameters:
  • agent_id (str) – ID of the agent that attempted the violation

  • attempted_path (str) – Path the agent tried to access

  • operation (str) – Operation attempted (e.g., “read”, “write”, “execute”)

Return type:

None

Examples

>>> manager.log_security_violation(
...     "agent-001",
...     "/etc/passwd",
...     "read"
... )

Notes

Currently logs to stderr. In production, this would write to a security audit log file.