Skip to content

feat(tasks): Add plan mode support for cloud runs with permission relay#54466

Merged
VojtechBartos merged 2 commits into
masterfrom
vojta/initial-perm-mode
Apr 15, 2026
Merged

feat(tasks): Add plan mode support for cloud runs with permission relay#54466
VojtechBartos merged 2 commits into
masterfrom
vojta/initial-perm-mode

Conversation

@VojtechBartos
Copy link
Copy Markdown
Member

@VojtechBartos VojtechBartos commented Apr 14, 2026

Problem

Plan mode doesn't work in cloud runs — the cloud agent auto-approves all permissions instantly, so plans are never reviewed. There's also no mode switcher UI for cloud sessions.

Changes

  • Relay permission requests (plan approvals, edits, bash) to connected PostHog Code desktop app via SSE instead of auto-approving
  • Enforce plan mode tool restrictions so the agent must plan before acting
  • Pass initial_permission_mode through the task run API so cloud sessions start in the correct mode (defaults to bypassPermissions when not set — web app/Slack tasks unaffected)
  • Show mode switcher in cloud session chat UI with all modes including bypass permissions
  • Backend: add initial_permission_mode field and permission_response/set_config_option commands

How did you test this code?

Publish to changelog?

No

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 14, 2026

Size Change: 0 B

Total Size: 129 MB

ℹ️ View Unchanged
Filename Size
frontend/dist/368Hedgehogs 5.26 kB
frontend/dist/abap 14.2 kB
frontend/dist/AccountSocialConnected 1.62 kB
frontend/dist/Action 23.2 kB
frontend/dist/Actions 1.02 kB
frontend/dist/AdvancedActivityLogsScene 34 kB
frontend/dist/AgenticAuthorize 5.25 kB
frontend/dist/apex 3.95 kB
frontend/dist/ApprovalDetail 16.2 kB
frontend/dist/array.full.es5.js 332 kB
frontend/dist/array.full.js 427 kB
frontend/dist/array.js 183 kB
frontend/dist/AsyncMigrations 13.1 kB
frontend/dist/AuthorizationStatus 716 B
frontend/dist/azcli 846 B
frontend/dist/bat 1.84 kB
frontend/dist/BatchExportScene 60.3 kB
frontend/dist/bicep 2.55 kB
frontend/dist/Billing 493 B
frontend/dist/BillingSection 20.8 kB
frontend/dist/BoxPlot 5.04 kB
frontend/dist/browserAll-0QZMN1W2 37.4 kB
frontend/dist/ButtonPrimitives 562 B
frontend/dist/CalendarHeatMap 4.79 kB
frontend/dist/cameligo 2.18 kB
frontend/dist/changeRequestsLogic 544 B
frontend/dist/CLIAuthorize 11.3 kB
frontend/dist/CLILive 3.97 kB
frontend/dist/clojure 9.64 kB
frontend/dist/coffee 3.59 kB
frontend/dist/Cohort 23.2 kB
frontend/dist/CohortCalculationHistory 6.22 kB
frontend/dist/Cohorts 9.39 kB
frontend/dist/ConfirmOrganization 4.48 kB
frontend/dist/conversations.js 65.8 kB
frontend/dist/Coupons 720 B
frontend/dist/cpp 5.3 kB
frontend/dist/Create 655 B
frontend/dist/crisp-chat-integration.js 1.88 kB
frontend/dist/csharp 4.52 kB
frontend/dist/csp 1.42 kB
frontend/dist/css 4.51 kB
frontend/dist/cssMode 4.15 kB
frontend/dist/CustomCssScene 3.55 kB
frontend/dist/CustomerAnalyticsConfigurationScene 1.99 kB
frontend/dist/CustomerAnalyticsScene 26.4 kB
frontend/dist/CustomerJourneyBuilderScene 1.69 kB
frontend/dist/CustomerJourneyTemplatesScene 7.39 kB
frontend/dist/customizations.full.js 17.9 kB
frontend/dist/CyclotronJobInputAssignee 1.32 kB
frontend/dist/CyclotronJobInputTicketTags 711 B
frontend/dist/cypher 3.38 kB
frontend/dist/dart 4.25 kB
frontend/dist/Dashboard 1.11 kB
frontend/dist/Dashboards 23.1 kB
frontend/dist/DataManagementScene 646 B
frontend/dist/DataPipelinesNewScene 2.32 kB
frontend/dist/DataWarehouseScene 1.21 kB
frontend/dist/DataWarehouseSourceScene 668 B
frontend/dist/Deactivated 1.13 kB
frontend/dist/dead-clicks-autocapture.js 13.1 kB
frontend/dist/DeadLetterQueue 5.38 kB
frontend/dist/DebugScene 20 kB
frontend/dist/decompressionWorker 2.85 kB
frontend/dist/decompressionWorker.js 2.85 kB
frontend/dist/DefinitionEdit 7.11 kB
frontend/dist/DefinitionView 22.7 kB
frontend/dist/DestinationsScene 2.71 kB
frontend/dist/dist 575 B
frontend/dist/dockerfile 1.87 kB
frontend/dist/EarlyAccessFeature 753 B
frontend/dist/EarlyAccessFeatures 2.84 kB
frontend/dist/ecl 5.33 kB
frontend/dist/EditorScene 896 B
frontend/dist/elixir 10.3 kB
frontend/dist/elk.bundled 1.44 MB
frontend/dist/EmailMFAVerify 2.98 kB
frontend/dist/EndpointScene 37.5 kB
frontend/dist/EndpointsScene 22.1 kB
frontend/dist/ErrorTrackingConfigurationScene 2.2 kB
frontend/dist/ErrorTrackingIssueFingerprintsScene 6.98 kB
frontend/dist/ErrorTrackingIssueScene 82.9 kB
frontend/dist/ErrorTrackingScene 12.9 kB
frontend/dist/EvaluationTemplates 575 B
frontend/dist/EventsScene 2.46 kB
frontend/dist/exception-autocapture.js 11.8 kB
frontend/dist/Experiment 210 kB
frontend/dist/Experiments 17.7 kB
frontend/dist/exporter 20.9 MB
frontend/dist/exporter.js 20.9 MB
frontend/dist/ExportsScene 3.86 kB
frontend/dist/FeatureFlag 128 kB
frontend/dist/FeatureFlags 606 B
frontend/dist/FeatureFlagTemplatesScene 7.03 kB
frontend/dist/FlappyHog 5.78 kB
frontend/dist/flow9 1.8 kB
frontend/dist/freemarker2 16.7 kB
frontend/dist/fsharp 2.98 kB
frontend/dist/go 2.65 kB
frontend/dist/graphql 2.26 kB
frontend/dist/Group 14.4 kB
frontend/dist/Groups 3.91 kB
frontend/dist/GroupsNew 7.34 kB
frontend/dist/handlebars 7.34 kB
frontend/dist/hcl 3.59 kB
frontend/dist/HealthCategoryDetailScene 7.23 kB
frontend/dist/HealthScene 10.3 kB
frontend/dist/HeatmapNewScene 4.16 kB
frontend/dist/HeatmapRecordingScene 3.92 kB
frontend/dist/HeatmapScene 5.88 kB
frontend/dist/HeatmapsScene 3.88 kB
frontend/dist/hls 394 kB
frontend/dist/HogFunctionScene 58.8 kB
frontend/dist/HogRepl 7.37 kB
frontend/dist/html 5.58 kB
frontend/dist/htmlMode 4.62 kB
frontend/dist/image-blob-reduce.esm 49.4 kB
frontend/dist/InboxScene 59.8 kB
frontend/dist/index 306 kB
frontend/dist/index.js 306 kB
frontend/dist/ini 1.1 kB
frontend/dist/InsightOptions 5.41 kB
frontend/dist/InsightScene 28.9 kB
frontend/dist/IntegrationsRedirect 733 B
frontend/dist/intercom-integration.js 1.93 kB
frontend/dist/InviteSignup 14.4 kB
frontend/dist/java 3.22 kB
frontend/dist/javascript 985 B
frontend/dist/jsonMode 13.9 kB
frontend/dist/julia 7.22 kB
frontend/dist/kotlin 3.4 kB
frontend/dist/lazy 150 kB
frontend/dist/LegacyPluginScene 26.6 kB
frontend/dist/LemonTextAreaMarkdown 502 B
frontend/dist/less 3.9 kB
frontend/dist/lexon 2.44 kB
frontend/dist/lib 2.22 kB
frontend/dist/Link 468 B
frontend/dist/LinkScene 24.8 kB
frontend/dist/LinksScene 4.19 kB
frontend/dist/liquid 4.53 kB
frontend/dist/LiveDebugger 19.1 kB
frontend/dist/LiveEventsTable 2.98 kB
frontend/dist/LLMAnalyticsClusterScene 15.7 kB
frontend/dist/LLMAnalyticsClustersScene 43.1 kB
frontend/dist/LLMAnalyticsDatasetScene 19.7 kB
frontend/dist/LLMAnalyticsDatasetsScene 3.28 kB
frontend/dist/LLMAnalyticsEvaluation 41.7 kB
frontend/dist/LLMAnalyticsEvaluationsScene 29.5 kB
frontend/dist/LLMAnalyticsPlaygroundScene 36.3 kB
frontend/dist/LLMAnalyticsScene 117 kB
frontend/dist/LLMAnalyticsSessionScene 13.4 kB
frontend/dist/LLMAnalyticsTraceScene 127 kB
frontend/dist/LLMAnalyticsUsers 526 B
frontend/dist/LLMASessionFeedbackDisplay 4.83 kB
frontend/dist/LLMPromptScene 20.6 kB
frontend/dist/LLMPromptsScene 4.21 kB
frontend/dist/Login 8.57 kB
frontend/dist/Login2FA 4.2 kB
frontend/dist/logs.js 38.5 kB
frontend/dist/LogsScene 11.3 kB
frontend/dist/lua 2.11 kB
frontend/dist/m3 2.81 kB
frontend/dist/main 819 kB
frontend/dist/ManagedMigration 14 kB
frontend/dist/markdown 3.79 kB
frontend/dist/MarketingAnalyticsScene 39.7 kB
frontend/dist/MaterializedColumns 10.2 kB
frontend/dist/Max 835 B
frontend/dist/mdx 5.39 kB
frontend/dist/memlens.lib.bundle 27.8 kB
frontend/dist/MessageTemplate 16.3 kB
frontend/dist/MetricsScene 828 B
frontend/dist/mips 2.58 kB
frontend/dist/ModelsScene 13.6 kB
frontend/dist/MonacoDiffEditor 403 B
frontend/dist/monacoEditorWorker 288 kB
frontend/dist/monacoEditorWorker.js 288 kB
frontend/dist/monacoJsonWorker 419 kB
frontend/dist/monacoJsonWorker.js 419 kB
frontend/dist/monacoTsWorker 7.02 MB
frontend/dist/monacoTsWorker.js 7.02 MB
frontend/dist/MoveToPostHogCloud 4.46 kB
frontend/dist/msdax 4.91 kB
frontend/dist/mysql 11.3 kB
frontend/dist/NavTabChat 4.68 kB
frontend/dist/NewSourceWizard 758 B
frontend/dist/NewTabScene 681 B
frontend/dist/NodeDetailScene 16.3 kB
frontend/dist/NotebookCanvasScene 3.2 kB
frontend/dist/NotebookPanel 5.21 kB
frontend/dist/NotebookScene 8.21 kB
frontend/dist/NotebooksScene 7.58 kB
frontend/dist/OAuthAuthorize 573 B
frontend/dist/objective-c 2.41 kB
frontend/dist/Onboarding 699 kB
frontend/dist/OnboardingCouponRedemption 1.2 kB
frontend/dist/pascal 2.99 kB
frontend/dist/pascaligo 2 kB
frontend/dist/passkeyLogic 484 B
frontend/dist/PasswordReset 4.32 kB
frontend/dist/PasswordResetComplete 2.94 kB
frontend/dist/PendingDeletion 2.21 kB
frontend/dist/perl 8.25 kB
frontend/dist/PersonScene 16.1 kB
frontend/dist/PersonsScene 4.68 kB
frontend/dist/pgsql 13.5 kB
frontend/dist/php 8.02 kB
frontend/dist/PipelineStatusScene 6.22 kB
frontend/dist/pla 1.67 kB
frontend/dist/posthog 137 kB
frontend/dist/postiats 7.86 kB
frontend/dist/powerquery 16.9 kB
frontend/dist/powershell 3.27 kB
frontend/dist/PreflightCheck 5.53 kB
frontend/dist/product-tours.js 115 kB
frontend/dist/ProductTour 273 kB
frontend/dist/ProductTours 4.68 kB
frontend/dist/ProjectHomepage 24.7 kB
frontend/dist/protobuf 9.05 kB
frontend/dist/pug 4.82 kB
frontend/dist/python 4.76 kB
frontend/dist/qsharp 3.19 kB
frontend/dist/QueryPerformance 5.66 kB
frontend/dist/r 3.12 kB
frontend/dist/razor 9.35 kB
frontend/dist/recorder-v2.js 111 kB
frontend/dist/recorder.js 111 kB
frontend/dist/redis 3.55 kB
frontend/dist/redshift 11.8 kB
frontend/dist/RegionMap 29.4 kB
frontend/dist/render-query 20.6 MB
frontend/dist/render-query.js 20.6 MB
frontend/dist/ResourceTransfer 9.17 kB
frontend/dist/restructuredtext 3.9 kB
frontend/dist/RevenueAnalyticsScene 25.6 kB
frontend/dist/ruby 8.5 kB
frontend/dist/rust 4.16 kB
frontend/dist/SavedInsights 664 B
frontend/dist/sb 1.82 kB
frontend/dist/scala 7.32 kB
frontend/dist/scheme 1.76 kB
frontend/dist/scss 6.41 kB
frontend/dist/SdkDoctorScene 9.4 kB
frontend/dist/SessionAttributionExplorerScene 6.62 kB
frontend/dist/SessionGroupSummariesTable 4.62 kB
frontend/dist/SessionGroupSummaryScene 17 kB
frontend/dist/SessionProfileScene 15.8 kB
frontend/dist/SessionRecordingDetail 1.73 kB
frontend/dist/SessionRecordingFilePlaybackScene 4.46 kB
frontend/dist/SessionRecordings 742 B
frontend/dist/SessionRecordingsKiosk 8.84 kB
frontend/dist/SessionRecordingsPlaylistScene 4.14 kB
frontend/dist/SessionRecordingsSettingsScene 1.9 kB
frontend/dist/SessionsScene 3.86 kB
frontend/dist/SettingsScene 2.98 kB
frontend/dist/SharedMetric 4.83 kB
frontend/dist/SharedMetrics 549 B
frontend/dist/shell 3.07 kB
frontend/dist/SignupContainer 24.5 kB
frontend/dist/Site 1.18 kB
frontend/dist/solidity 18.6 kB
frontend/dist/sophia 2.76 kB
frontend/dist/SourcesScene 5.96 kB
frontend/dist/sourceWizardLogic 696 B
frontend/dist/sparql 2.55 kB
frontend/dist/sql 10.3 kB
frontend/dist/SqlVariableEditScene 7.24 kB
frontend/dist/st 7.4 kB
frontend/dist/StartupProgram 21.2 kB
frontend/dist/SubscriptionsScene 16.4 kB
frontend/dist/SupportSettingsScene 1.16 kB
frontend/dist/SupportTicketScene 23.7 kB
frontend/dist/SupportTicketsScene 733 B
frontend/dist/Survey 848 B
frontend/dist/SurveyFormBuilder 1.54 kB
frontend/dist/Surveys 18.2 kB
frontend/dist/surveys.js 90 kB
frontend/dist/SurveyWizard 64.2 kB
frontend/dist/swift 5.26 kB
frontend/dist/SystemStatus 16.8 kB
frontend/dist/systemverilog 7.61 kB
frontend/dist/TaskDetailScene 21.5 kB
frontend/dist/TaskTracker 13.2 kB
frontend/dist/tcl 3.57 kB
frontend/dist/TextCardMarkdownEditor 11 kB
frontend/dist/toolbar 10.7 MB
frontend/dist/toolbar.js 10.7 MB
frontend/dist/ToolbarLaunch 2.52 kB
frontend/dist/tracing-headers.js 1.74 kB
frontend/dist/TracingScene 29.8 kB
frontend/dist/TransformationsScene 1.95 kB
frontend/dist/tsMode 24 kB
frontend/dist/twig 5.97 kB
frontend/dist/TwoFactorReset 3.98 kB
frontend/dist/typescript 240 B
frontend/dist/typespec 2.82 kB
frontend/dist/Unsubscribe 1.62 kB
frontend/dist/UserInterview 4.53 kB
frontend/dist/UserInterviews 2.01 kB
frontend/dist/vb 5.79 kB
frontend/dist/VercelConnect 4.95 kB
frontend/dist/VercelLinkError 1.91 kB
frontend/dist/VerifyEmail 4.48 kB
frontend/dist/vimMode 211 kB
frontend/dist/VisualReviewRunScene 19.4 kB
frontend/dist/VisualReviewRunsScene 5.54 kB
frontend/dist/VisualReviewSettingsScene 10.8 kB
frontend/dist/web-vitals.js 6.39 kB
frontend/dist/WebAnalyticsScene 5.77 kB
frontend/dist/WebGLRenderer-DYjOwNoG 60.3 kB
frontend/dist/WebGPURenderer-B_wkl_Ja 36.3 kB
frontend/dist/WebScriptsScene 2.57 kB
frontend/dist/webworkerAll-puPV1rBA 324 B
frontend/dist/wgsl 7.34 kB
frontend/dist/Wizard 4.45 kB
frontend/dist/WorkflowScene 102 kB
frontend/dist/WorkflowsScene 46.9 kB
frontend/dist/WorldMap 4.73 kB
frontend/dist/xml 2.98 kB
frontend/dist/yaml 4.6 kB

compressed-size-action

@VojtechBartos VojtechBartos force-pushed the vojta/initial-perm-mode branch from 196dc82 to 0fcddef Compare April 14, 2026 19:46
@VojtechBartos VojtechBartos self-assigned this Apr 14, 2026
@VojtechBartos VojtechBartos requested a review from a team April 14, 2026 20:35
@VojtechBartos VojtechBartos marked this pull request as ready for review April 14, 2026 20:35
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 14, 2026

Comments Outside Diff (1)

  1. products/tasks/backend/serializers.py, line 461-468 (link)

    P2 Missing params validation for new command methods

    The validate method enforces a non-empty content for user_message, but permission_response and set_config_option receive no server-side params validation. A caller that omits required fields (e.g., a decision value for permission_response) will only get an error from the agent server, not from this serializer. Adding at minimum a presence check for each new method would give earlier, clearer feedback and keep the pattern consistent.

    (Adjust field names to match what the agent server actually expects.)

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: products/tasks/backend/serializers.py
    Line: 461-468
    
    Comment:
    **Missing params validation for new command methods**
    
    The `validate` method enforces a non-empty `content` for `user_message`, but `permission_response` and `set_config_option` receive no server-side params validation. A caller that omits required fields (e.g., a decision value for `permission_response`) will only get an error from the agent server, not from this serializer. Adding at minimum a presence check for each new method would give earlier, clearer feedback and keep the pattern consistent.
    
    (Adjust field names to match what the agent server actually expects.)
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: products/tasks/backend/serializers.py
Line: 461-468

Comment:
**Missing params validation for new command methods**

The `validate` method enforces a non-empty `content` for `user_message`, but `permission_response` and `set_config_option` receive no server-side params validation. A caller that omits required fields (e.g., a decision value for `permission_response`) will only get an error from the agent server, not from this serializer. Adding at minimum a presence check for each new method would give earlier, clearer feedback and keep the pattern consistent.

(Adjust field names to match what the agent server actually expects.)

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "chore: update OpenAPI generated types" | Re-trigger Greptile

@VojtechBartos VojtechBartos merged commit 6e3fe73 into master Apr 15, 2026
241 checks passed
@VojtechBartos VojtechBartos deleted the vojta/initial-perm-mode branch April 15, 2026 12:01
pauldambra pushed a commit that referenced this pull request Apr 15, 2026
…ay (#54466)

Co-authored-by: tests-posthog[bot] <250237707+tests-posthog[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@tatoalo tatoalo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all good, adding review here to address as follow up

  1. bypassPermissions is accepted from any caller — no authorization gate
    initial_permission_mode accepts "bypassPermissions" as a valid choice directly from the API. Any authenticated user with task:write scope can start a run in bypass-permissions mode. The PR description says this is the default when the field is unset (for web/Slack tasks), but there's no distinction between "default fallback" and "explicitly requested by an arbitrary API caller."

If bypass-permissions is meant to be a privileged mode (e.g., only for unattended web/Slack tasks, or only when no desktop app is connected), the backend should enforce that — not rely on callers to be well-behaved. Consider either:

Removing bypassPermissions from the API-accepted choices and having the agent server fall back to it internally when no mode is set
Adding an authorization check (e.g., only allow bypass when run_source is not from a connected desktop client)

  1. Zero test coverage
    None of the new functionality has tests:

No tests for initial_permission_mode on TaskRunCreateRequestSerializer (valid choices, None default, state plumbing)
No tests for permission_response / set_config_option being accepted in TaskRunCommandRequestSerializer
No tests for the extra_state assembly logic in api.py (especially the interaction between pending_user_message and initial_permission_mode both being set)
This is a security-sensitive feature (permission relay / mode switching). Tests should cover at least the serializer validation and the state assembly.

  1. initial_permission_mode is stored in state but never consumed in this codebase
    The value goes into TaskRun.state via extra_state, but:

RunState (Pydantic model with extra="allow") doesn't declare it as a typed field — it's silently absorbed into extras
TaskProcessingContext doesn't reference it
start_agent_server activity doesn't read or pass it to the sandbox
Neither sandbox implementation's start_agent_server() method accepts it
The entire consumption presumably happens in the companion posthog/code repo (PR #1645), where the agent-server reads the value from TaskRun.state. This means:

The field is invisible to type checking in the PostHog backend
If the companion code regresses or changes how it reads state, the PostHog backend has no way to catch it
RunState should declare initial_permission_mode: str | None = None for type safety and discoverability

  1. No param validation for new command methods
    The validate method in TaskRunCommandRequestSerializer only validates params for user_message. The two new methods accept arbitrary DictField params with no schema enforcement:

def validate(self, attrs):
method = attrs["method"]
params = attrs.get("params", {})
if method == "user_message":
content = params.get("content")
if not content or not isinstance(content, str) or not content.strip():
raise serializers.ValidationError(...)
return attrs
# ← permission_response and set_config_option: no validation
The agent server presumably validates these downstream, but this makes the PostHog API an essentially open proxy for arbitrary JSON payloads to the sandbox, limited only by method name. For defense in depth:

permission_response should at minimum validate expected fields (e.g., id, result)
set_config_option should validate key and value presence

  1. Stale API description on command endpoint
    The @validated_request decorator description still reads:

"Forward a JSON-RPC command to the agent server running in the sandbox. Supports user_message, cancel, and close commands."

This should be updated to include permission_response and set_config_option.

@deployment-status-posthog
Copy link
Copy Markdown

deployment-status-posthog Bot commented Apr 15, 2026

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-04-15 12:28 UTC Run
prod-us ✅ Deployed 2026-04-15 12:45 UTC Run
prod-eu ✅ Deployed 2026-04-15 12:46 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants