p.enthalabs

Jules Turndown

Skip to content

![Image 1: Jules logo!Image 2: Jules logo Jules](https://jules.google/docs/)

Search Ctrl K

Cancel

Select theme

- Docs

- Changelog

- REST API

- Guides

- Jules Tools (CLI)

- Integrations

- All Updates

- Jules Turndown Oct 29, 2026

- Gemini 3.1 Pro is now available in Jules Mar 09, 2026

- Auto-Fixing CI Failures and configure Jules to commit as you Feb 19, 2026

- MCP support comes to Jules Feb 02, 2026

- Gemini 3 Flash is now the base model in Jules Jan 30, 2026

- Introducing the Planning Critic for Auto-Approved Plans Jan 26, 2026

- Jules now finds performance optimizations Jan 26, 2026

- REST API: Repoless, File Outputs, and Activity Filters Jan 26, 2026

- Update Scheduled Tasks Jan 26, 2026

- Enable suggested tasks to let Jules find issues proactively Dec 10, 2025

- Put routine maintenance on autopilot with Scheduled Tasks Dec 10, 2025

- Automated fixes for Render deployments Dec 10, 2025

- Start from scratch—instantly Nov 20, 2025

- Introducing Gemini 3 Pro Nov 19, 2025

- New Jules Tools CLI Updates: Side-by-Side Diffs, Repo Inference, and More Nov 10, 2025

- Introducing the Jules API Oct 03, 2025

- Jules in the command line Oct 02, 2025

- Use Environment Variables In Jules Oct 01, 2025

- Jules gains memory!Sep 30, 2025

- Tell Jules exactly what file to work on using file selector Sep 29, 2025

- Jules Acts on PR Feedback Sep 23, 2025

- All Hands on Deck!Sep 19, 2025

- Image upload Sep 09, 2025

- Stacked Diff Sep 04, 2025

- Improved Jules Critic Sep 03, 2025

- Jules Sample Prompts Sep 02, 2025

- Render images in the diff viewer Aug 22, 2025

- Export at any time Aug 15, 2025

- Increasing the VM Size to 20GB Aug 15, 2025

- Jules can surf the web Aug 08, 2025

- Interactive Plan Aug 08, 2025

- Critic Agent Aug 08, 2025

- Jules can test web-apps and show you the results Aug 07, 2025

- Jules is out of beta!Aug 06, 2025

- Environment snapshots for faster tasks Aug 05, 2025

- Open A PR directly from Jules Aug 04, 2025

- Added Bun runtime support Jul 18, 2025

- Improved task controls and other 💅 UI delight Jul 03, 2025

- Jules now listens to GitHub issues Jun 26, 2025

- Jules Agent Update: Faster, Smarter, More Reliable Jun 20, 2025

- Modernized base environment and updated toolchains Jun 18, 2025

- Customization and Efficiency Enhancements Jun 06, 2025

- A faster, smoother and more reliable Jules May 30, 2025

- Improving Stablity May 22, 2025

- Jules is here May 19, 2025

On this page

- Overview

Jules Turndown

October 29, 2026

We’re writing to let you know that as part of our work to unify our agentic coding efforts, Jules will wind down on December 31, 2026. You have until November 11, 2026 to continue finishing up sessions. After November 11, 2026, we will be turning Jules to read-only until the end of the year.

When we launched Jules, it was an experiment to learn how asynchronous coding agents could help you tackle your backlog and ship faster. What you built with it taught us where agentic development is headed, and those learnings are shaping products across Google, including our agent-first platform, Google Antigravity.

You can now export everything Jules knows about your work into a local folder: account settings, environment variables, scheduled tasks, connected repositories, memories, setup scripts, and every session, including its prompt, plan, full activity log, and code patches.

Your code, branches, and pull requests already live in GitHub, so they stay where they are. The export covers the configuration and history that live inside Jules.

To export, install Jules Tools and sign in:

Terminal window

`npm install -g @google/julesjules login`

Then open a CLI coding agent, such as Claude Code, from your home directory and paste the export prompt below. The agent checks your setup, runs the export, and tells you what it saved.

Show the export prompt

Export prompt

```

I want to export all my data from Google Jules into a local folder: settings, environmentvariables, scheduled tasks, connected repos, memories, setup scripts, and every session (prompt,plan, full activity log, and code patches). Please do this in order:

1. Setup - Check whether the Jules CLI is installed (`which jules`). If it isn't, install it with `npm install -g @google/jules`. If npm isn't installed, tell me and stop. - Check whether I'm logged in: `security find-generic-password -s jules-cli -a default` on macOS (metadata only, without -w), or `secret-tool lookup service jules-cli username default` on Linux. If there's no entry, ask me to run `! jules login` myself. It's an interactive browser sign-in, so don't try to run it for me. Wait until I say it's done. - Run `jules remote list --repo`. If it fails with a 401 and asks about GitHub, tell me to connect my GitHub account at https://github.com/apps/google-labs-jules/installations/select_target and wait for me to confirm. If I've never used Jules with GitHub repos, I can skip this; the export will just have no repo data. 2. Export: save the script below to a file and run it from my home directory. Then tell me what was exported (the counts it prints) and the full path of the folder. Don't print my access token or the values in env-variables.json.

Problems someone else already ran into:- The Jules CLI stores its login in the macOS Keychain (service "jules-cli", account "default") as "go-keyring-base64:<base64 JSON>". The script decodes that. The access token expires about an hour after login; if you get 401s on every call, run any `jules` command or ask me to run `! jules login` again.- If ListSources returns 401 "missing required authentication credential" but the other calls work, my GitHub account isn't connected to Jules (see step 1).- Settings, env vars, repos and memories come from an internal `$rpc` endpoint. Sessions come from REST endpoints under https://aida.googleapis.com/v1/swebot (/tasks, /tasks/{id}, /tasks/{id}/activities), which are what the CLI itself uses. Both are undocumented, so if a call starts returning 404/400, tell me which one rather than guessing at fixes.- The repo list doesn't include setup scripts or test commands; the script recovers them from each session's code output (repoMetadata). Empty memories responses ({}) just mean there are no memories.- The API may return a few more sessions than `jules remote list --session` shows (older ones). That's expected. ```pythonimport base64, json, pathlib, re, subprocess, sys, urllib.error, urllib.parse, urllib.request

def get_token(): for cmd in [["security", "find-generic-password", "-s", "jules-cli", "-a", "default", "-w"], ["secret-tool", "lookup", "service", "jules-cli", "username", "default"]]: try: out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL).decode().strip() if out.startswith("go-keyring-base64:"): out = base64.b64decode(out.split(":", 1)[1]).decode() if out: return json.loads(out)["access_token"] except Exception: pass p = pathlib.Path.home() / ".jules/cache/oauth_creds.json" if p.exists(): return json.loads(p.read_text())["access_token"] sys.exit("Run `jules login` first.")

TOKEN = get_token()HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}RPC = "https://aida.googleapis.com/$rpc/language_labs.aida.swebot.proto.SweBotService"REST = "https://aida.googleapis.com/v1/swebot"OUT = pathlib.Path("./jules-export"); OUT.mkdir(exist_ok=True)errors = []

def rpc(m, b=None): req = urllib.request.Request(f"{RPC}/{m}", data=json.dumps(b or {}).encode(), headers=HEADERS, method="POST") with urllib.request.urlopen(req, timeout=60) as r: return json.loads(r.read().decode() or "{}")

def get(path, **params): q = ("?" + urllib.parse.urlencode(params)) if params else "" with urllib.request.urlopen(urllib.request.Request(f"{REST}{path}{q}", headers=HEADERS), timeout=60) as r: return json.loads(r.read().decode() or "{}")

def paged(fetch, key): items, token = [], None while True: resp = fetch(token) items += resp.get(key, []) token = resp.get("nextPageToken") if not token: return items

def safe(s): return re.sub(r"[^a-zA-Z0-9._-]", "_", s)def dump(path, obj): path.parent.mkdir(parents=True, exist_ok=True); path.write_text(json.dumps(obj, indent=2))

Account-level datadump(OUT / "user-settings.json", rpc("GetUserSettings"))dump(OUT / "env-variables.json", rpc("ListEnvironmentVariables"))dump(OUT / "scheduled-tasks.json", rpc("ListScheduledTasks"))

Repos (sources) and their memoriessources = paged(lambda t: rpc("ListSources", {"pageSize": 100, **({"pageToken": t} if t else {})}), "sources")dump(OUT / "sources.json", sources)mem_repos = 0for src in sources: sid = src.get("sourceId") or src.get("id") or src.get("name", "").removeprefix("sources/") try: mems = paged(lambda t: rpc("ListMemories", {"sourceId": sid, "pageSize": 100, **({"pageToken": t} if t else {})}), "memories") except urllib.error.HTTPError as e: errors.append(f"memories {sid}: HTTP {e.code}"); continue if mems: mem_repos += 1 d = OUT / "repos" / safe(sid) dump(d / "memories.json", mems) (d / "memories.md").write_text("# Memories\n\n" + "\n".join( f"- {m.get('Fact') or m.get('fact') or m.get('content')}" for m in mems if not m.get("archived")) + "\n")

Sessions: full detail, activity log, patches, and a readable summarysessions = paged(lambda t: get("/tasks", pageSize=100, **({"pageToken": t} if t else {})), "tasks")dump(OUT / "sessions.json", sessions)setup = {} # latest setup script / test command seen per repopatches = 0for s in sorted(sessions, key=lambda s: s.get("createdAt", "")): tid = s["id"]; d = OUT / "sessions" / tid try: task = get(f"/tasks/{tid}").get("task", {}) acts = paged(lambda t: get(f"/tasks/{tid}/activities", pageSize=100, **({"pageToken": t} if t else {})), "activitySteps") except urllib.error.HTTPError as e: errors.append(f"session {tid}: HTTP {e.code}"); continue dump(d / "session.json", task) dump(d / "activities.json", acts) commits = [o["gitCommit"] for o in task.get("outputs", []) if "gitCommit" in o] for i, c in enumerate(commits, 1): if c.get("patch", {}).get("unidiff"): (d / f"patch-{i}.diff").write_text(c["patch"]["unidiff"]); patches += 1 meta = c.get("repoMetadata", {}) if meta.get("environmentSetupScript") or meta.get("testCommand"): setup[task.get("sourceId") or meta.get("name") or tid] = meta plan = task.get("latestPlan", {}).get("steps", []) kinds = {} for a in acts: for actor, v in a.items(): if isinstance(v, dict): for k in v: kinds[f"{actor}.{k}"] = kinds.get(f"{actor}.{k}", 0) + 1 lines = [f"# {task.get('title') or s.get('suggestedTitle') or tid}", "", f"- **ID:** {tid}", f"- **Repo:** {task.get('sourceId', '')}", f"- **Status:** {task.get('taskStatus', '')}", f"- **Created:** {task.get('createdAt', '')}", f"- **Completed:** {task.get('completedAt', '')}", "", "## Prompt", "", task.get("description", ""), ""] if plan: lines += ["## Latest plan", ""] + [f"{p.get('index', 0) + 1}. {p.get('title', '')}" for p in plan] + [""] if commits: lines += ["## Code outputs", ""] + [ f"- `patch-{i}.diff`: {c.get('title') or (c.get('commitMessage') or '').split(chr(10))[0]} (branch `{c.get('gitBranchName', '')}`)" for i, c in enumerate(commits, 1)] + [""] if pub := task.get("latestPublish", {}).get("commitInfo"): lines += ["## Published", "", f"- Commit `{pub.get('commitId', '')}` on `{pub.get('branchName', '')}`", ""] lines += ["## Activity", "", f"{len(acts)} steps (full log in `activities.json`):", ""] + [f"- {k}: {n}" for k, n in sorted(kinds.items())] (d / "summary.md").write_text("\n".join(lines) + "\n")

for sid, meta in setup.items(): d = OUT / "repos" / safe(sid); d.mkdir(parents=True, exist_ok=True) if meta.get("environmentSetupScript"): (d / "setup.sh").write_text(meta["environmentSetupScript"] + "\n") if meta.get("testCommand"): (d / "test-command.txt").write_text(meta["testCommand"] + "\n")

print(json.dumps({"repos": len(sources), "repos_with_memories": mem_repos, "sessions": len(sessions), "patches": patches, "repos_with_setup_or_test": len(setup), "error_count": len(errors), "errors": errors[:10]}, indent=2))print(f"Exported all Jules data to {OUT.resolve()}")``` ```

Your data lands in `~/jules-export`: connected repositories in `sources.json`, a folder per repository with its setup script, test command, and memories, your settings, environment variables, and scheduled tasks as JSON, and a folder per session with a readable `summary.md`, the full activity log, and its diffs.

`env-variables.json` contains your environment variable values, so keep the export folder private and out of your repositories. If you use Jules with GitHub, make sure your GitHub account is connected first, or the export won’t include repository data.

Previous All UpdatesNext Gemini 3.1 Pro is now available in Jules