Skip to content

Workspaces and runtimes ​

Goal: preserve storage-provider semantics and boundaries when changing paths, edits or PRoot behavior.

Open
View on GitHub

Workspace abstraction ​

workspace/WorkspaceManager.kt distinguishes content URIs with persistent directory grants, file shared-storage wrappers and PRoot's dedicated scheme with Linux ID. Picker labels, URIs and real paths are not interchangeable.

ResponsibilityFiles relative to the Kotlin package directory
URI/grants/rootworkspace/WorkspaceManager.kt, GrantedWorkspaceDirectory.kt
Shared-storage wrapperworkspace/SharedStorageWorkspace.kt
PRoot guest/host mappingworkspace/ProotWorkspace.kt, ProotPathResolver.kt
IO and indexworkspace/NativeFileManager.kt, GlobalFileManager.kt, WorkspaceFileIndexer.kt
Agent mutation/diffai/agent/AgentFileToolHandler.kt, ai/AgentFileMutation.kt, ai/AgentTextEdits.kt

Custom DocumentFile implementations are under app/src/main/java/androidx/documentfile/provider/. Not every document has a bindable filesystem path.

Paths and mutations ​

Workspace tools accept relative paths and validate confinement to the root. Global tools have separate shared-storage scope and restricted directories; do not add unrestricted absolute-path access to ordinary tools.

Exact edits validate match counts; line ranges are inclusive and one-based. Preserve before/after/diff recording, conflict checks and sub-agent write coordination because content may change after the initial read.

PRoot lifecycle ​

Under app/src/debianRuntime/java/.../debian/, ProotLinuxManager.kt manages instances/processes, ProotArchitecture.kt reads runtime ELF architecture, and ProotCommandExecutor.kt / DebianCommandExecutor.kt handle calls.

Keep IDs, rootfs and enabled state distinct. Validate archives, paths, shells and architecture in staging before activation. Rootfs is user data and must not be replaced during app updates based on seed versions. Close corresponding terminal and retained processes before disable/delete.

Foreground timeout affects that invocation. Background services retain their PRoot supervisor; later commands must not kill earlier services. Mounts reflect permissions at process startup, so changed permissions require reconnection.

Verification ​

Cover SAF, direct shared paths and PRoot-internal directories, plus traversal, symlinks, missing files, revoked grants and concurrent edits. Run GrantedWorkspacePathTest, ProotPathResolverTest, ProotCommandPreparationTest and ProotArchitectureTest, then device tests for real mounts and process lifecycle.

User-visible behavior belongs in Workspaces.

WorkspaceManager API ​

Selection and resolution ​

MethodContract
persistWorkspace(uri)Save selection/grants and return the stored URI string
setActiveWorkspaceUri(uri)Switch reference; does not grant a new directory
activeWorkspaceUri() / rootUri()Return stored/parsed reference
root()Nullable DocumentFile root
prootLinuxId() / prootGuestPath()Instance and guest directory from PRoot URI
displayName() / displayPath()Display values, not execution paths
termuxRootPath() / termuxPath(relativePath)Attempt command-path mapping; may be unavailable
searchFiles(query, limit) / invalidateFileIndex()File-reference lookup and invalidation

Read-only example ​

kotlin
// Existing host objects; keep Result failure semantics on IO.
val content = withContext(Dispatchers.IO) {
    check(workspaceManager.root() != null) { "Select a workspace first" }
    nativeFileManager.readFile("README.md").getOrThrow()
}

Reuse managers instead of assembling private Android paths from display values. Invalidate indexes after changes so search does not retain stale entries.

Mutations and editor cooperation ​

Read old content and compute a precise edit before using the AgentFileToolHandler ownership path. NotHandled, Applied and failure control fallback, duplicate writes and aborts respectively; see hooks. After a successful write, generate FileDiff and notify mutations. An empty diff must not hide failure.

Runtime separation example ​

An SAF-only workspace can support DocumentFile IO without having a bindable command path. PRoot projects use Linux ID/guest paths; a private host root is not a Termux path.

For “edit succeeds but build cannot find it”, compare workspace URI, Linux ID, command pwd and target file. Establish that all operations refer to the same copy before changing mounts or permissions.

Lyra Code. All rights reserved.