AppSheet Parser Suite: Analyze and Clean Up Your Apps

Good news — this is already fixed!

I was able to reproduce and fix the bug. It turned out to be a latent defect in actions_parser.py: a variable (actual_table) was only being initialized inside a conditional branch, so any action without a source table — which can happen with certain group actions or system-generated actions — would crash Phase 4. The fix initializes the variable up front so it always has a value.

Large apps are more likely to hit this because they’re more likely to contain an action that trips the condition, so your guess that “a ton of actions” was related wasn’t far off — it’s really “at least one action of a particular kind.”

While debugging, I also fixed a second issue that affects large apps: Python’s CSV reader has a default field-size limit of 128 KB, and apps with long formula expressions can exceed it. That one was raising warnings in Phase 5 and crashing the final summary. Both fixes are now on GitHub:

:backhand_index_pointing_right: GitHub - KirkMasden/appsheet_parser_and_orphan_detector: Python tools for AppSheet developers: Convert HTML Application Documentation to CSV format, analyze component dependencies, and identify unused (orphan) elements for cleanup. · GitHub

The commit with the fix: cd9eaac

Just re-download the ZIP (green “Code” button → Download ZIP) and replace your scripts folder — no need to share your app data. Give it a try and let me know how it goes!

P.S. I used Claude both for the debugging and for the initial draft of this post. But, to the best of my knowledge, what Claude has done and written is correct.

4 Likes

Thank you Kirk, the new fix worked and your entire parser worked through the entire process.

Oh boy I have a lot of cleaning up to do haha. It seems one’s cleaning up behaviour in the coding world actually mirrors their cleaning up behaviour in the real world….sigh.

Thank you once again Kirk, brilliant tool and very much needed.

Cheers! Leon

3 Likes

Great! In regard to the clean up, please be careful. The scripts may produce false positives. I worked pretty hard to get the scripts to the point that they didn’t produce false positives on my own primary app (my biggest one) but yours may be different from mine. If you find that there are false positives and are willing to share some details about them (or maybe even a version of your app that is stripped of data so that I can go into the editor and look around) I’ll try to tighten them up. Parsing all of the possible relationships on AppSheet apps is pretty complicated so I won’t be surprised if there are still relationships that the scripts fail to see.

Take care!

Kirk

4 Likes

Hey, this is actually pretty interesting work :eyes:

I’ve dealt with AppSheet apps getting messy over time, and honestly the “technical debt” part you mentioned hits hard. Once an app grows past a certain point, you stop remembering what is still used and what is just sitting there doing nothing.

I faced something similar in a client project where views and actions kept piling up after small updates. We only realized later half the stuff wasn’t even connected anymore, but cleaning it manually was painful and risky.

What worked for me was:

  • first mapping main flows manually (just core user paths)

  • then tagging “probably unused” components before deleting anything

  • and keeping a simple change log going forward (saved us later)

I’ve seen similar cleanup problems while structuring app systems for (URL Removed by Staff) workflows too.

Do you think this kind of tool works better for large legacy apps only, or even small apps can benefit early

7 Likes

Thanks for your kind comments.

Definitely good for the big ones in my view. Not sure about the value for small ones.

2 Likes

Thanks for this.

I have run it successfully for one of my apps - I now have a lot of data to go through!!

I am running Windows 11. On my first attempts I run into this issue

File “C:\Users\xxxx\Desktop\AppSheet Analyser\appsheet_parser_and_orphan_detector-main\master_parser_and_orphan_detector.py”, line 13, in
csv.field_size_limit(sys.maxsize)
OverflowError: Python int too large to convert to C long

I had to edit the master_parser_and_orphan_detector.py file and change line 13 from

csv.field_size_limit(sys.maxsize)

to

csv.field_size_limit(2147483647)

It then ran OK.

1 Like

Thank you very much for this valuable information! I’ll update the script as soon as I can get around to it. :slight_smile:

1 Like

Thanks a lot, brother!

2 Likes

Thank YOU! Actually, I’ve been a bit distracted with other projects recently and haven’t gotten around to making the fixes yet but I hope to be able to do that soon.

I’m also planning to update the scripts to make them more AI friendly. If one is programming in a conventional programming language, it’s quite easy to get help from AI. AppSheet is easy to learn but the interface makes getting help from AI harder. I’m hoping that my set of scripts, with a little bit of tweaking, can make it possible for something like Claude Code to help one with app editing – if only as a guide.

4 Likes

Apologies for the long silence. I’ve finally found time to return to this project.

Today, Claude and I fixed the Windows crash. Until now, the scripts raised Python’s CSV field size limit to the largest number the machine can count to. That works on a Mac. But as @ghost5 kindly pointed out back in May, on Windows that number is too large for the setting to hold, so the tool crashed at startup — meaning it simply didn’t work for Windows users at all. The limit is now capped at a value every platform accepts, still far larger than any real field.

There was a wider problem behind it. That call lived in only one of the eighteen scripts, so anyone running one of the others on its own got no raised limit at all and could hit the “field larger than field limit” error the call was meant to prevent. The limit is now set in a small shared module that every script imports, so it applies however you run things.

Sorry it took this long. I don’t have a Windows machine to test on — if you’re on Windows, I’d be grateful to hear whether it now runs for you.

Next I plan to tackle a more serious problem: false positives in the orphan detector. The tool’s job is to find components — views, slices, columns, actions — that are no longer used anywhere in your app, so you can safely delete them. It does that by following every reference it can find. But as @leonsteber kindly pointed out to me in May, there are four kinds of reference it doesn’t currently follow, which means components that are genuinely in use can be reported as orphans. Delete one on the tool’s say-so and you break your app. My thanks to him for the report, and for the detailed examples that came with it — I have test data for all four.

The four are: views reached only through LINKTOVIEW() inside actions; views referenced only via “Related” virtual columns; views contained in dashboards; and slices referenced only inside column-level expressions such as suggested values or initial values.

The tool has always reported candidates rather than confirmed orphans — hence the “potential” in the output filenames. That won’t change when these four are fixed. It can only follow references it knows how to look for, so anything it can’t see still looks like disuse. Please check for yourself that a component really is unused before deleting it.

After that, two larger additions: making the analysis usable by AI assistants, and extending it to the backing Google Sheet so the formulas and data there are visible alongside the app itself. More on both when they’re further along.

I’ve also added a STATUS.md file to the repository listing known defects, so you can see what’s outstanding without having to ask.

3 Likes

Note: Claude drafted this post. I have read it and modified parts but, to save time, I’ve relied on Claude’s prose in most of the post.

Progress at last — the false positives are fixed

Back in May, @leonsteber pointed out four kinds of reference the orphan detector wasn’t following, and in July I said I’d get to them. It took until the end of August, but they’re done, along with quite a bit more.

Leon also did something more generous than filing a report: he sent me a copy of his app. That turned out to matter more than any individual bug he named. I had spent months tuning the scripts against my own app, and the trouble with that is you can only fix what your own app happens to exercise. Every defect I found in the last week has the same shape — a rule that got written for the cases my app used and never for the rest. LINKTOFILTEREDVIEW wasn’t in the parser’s list of navigation functions at all. LINKTOFORM and new-record form actions were being excluded by an action-type filter, so those navigations were invisible. Map views had no visibility rule. “Primary” position on a table view was answered wrongly. A condition wrapped in NOT() was being read with its sense reversed.

The effect on Leon’s app is easier to show than describe. When I first ran the scripts on it, they reported 105 views as possible orphans. Running them now, on exactly the same export, they report 54. Fifty-one of those were the scripts’ errors — views that were reachable all along by routes the scripts couldn’t see. Slices, format rules and unused system views all came down substantially too.

So if you tried the tool and found the output noisy, it is worth another run. :slight_smile:

Thanks also to @ghost5 for the Windows report, which is fixed as well, and to everyone who has written in. I want to be honest that I am slow — this is a side project, and work and other things regularly take me away from it for weeks or months at a time. But I do try to act on feedback eventually, and a copy of an app is the most useful thing anyone can send me. If you’re willing to share one, even stripped of data, I’m sure it will help me find bugs I could not find on my own.

Still not a list of confirmed orphans

The output filenames say “potential” and they still mean it. The scripts follow the references they know how to look for, and I keep finding kinds they don’t. Please check a component yourself before deleting it.

Two things I’ve learned recently are worth stating plainly. The first is that the scripts may report something as unused when, in fact, it is in use. That’s what the fixes above address, and there are less false positives for “orphans” now, but it’s still a work in progress.

The second is the opposite, and it’s newer to me. The scripts may report a navigation route that cannot actually be taken. A button can be defined perfectly and still never appear on any screen — because a condition on it can never be true, or because the column it’s attached to is hidden in exactly the situation where the button would apply. I found one of these in my own app this week, and the scripts had cleared the view it leads to as reachable. It isn’t.

I’ve written up both directions, with specifics, in STATUS.md in the repository. It’s a real defect list rather than a summary, and it now includes findings I haven’t fixed yet.

Where this is going: making apps visible to AI

This is the part I’m most interested in, and it’s the reason for the work above.

If you’re writing in a conventional programming language, getting help from AI is easy — the code is right there to read. AppSheet is easier to learn than a programming language, but it’s much harder to get help with, because your app isn’t a text you can hand to anyone. It’s spread across an editor with no single place to look.

There’s a specific thing this makes hard, and it’s the thing I keep running into. Looking at a screen and asking why something appears is easy; everything has already resolved, and the editor will tell you which action produced the button. But going the other way — starting from an action or a column and asking where it shows up, or whether it shows up at all — is a different kind of problem. There isn’t isn’t a simple way to figure out the answer. It takes some detective work. That sort of detective work is what you need to do to clean up an app or when your trying to understand an app you inherited.

Converting the app definition to CSV is what makes that question answerable, and it’s why the export layer matters as much as the analysis built on top of it. As of today the repository includes a CLAUDE.md file (and an identical AGENTS.md for other tools) describing the CSV schemas, which script answers which kind of question, and — importantly — what the scripts can’t see. If you point Claude Code or a similar tool at the repository, it now has enough to use the output properly instead of guessing at it.

The next step is larger: making the backing Google Sheet visible too, formulas included. Right now the scripts can see your app’s structure but nothing of the computation happening in the sheet behind it. There’s also something I only realized this week — with the sheet data available, it becomes possible to ask why a particular button isn’t showing on a particular record, and get an actual answer rather than a list of conditions to check by hand. That’s further off, but it’s where I’d like this to end up.

GitHub: GitHub - KirkMasden/appsheet_parser_and_orphan_detector: Python tools for AppSheet developers: Convert HTML Application Documentation to CSV format, analyze component dependencies, and identify unused (orphan) elements for cleanup. · GitHub
Documentation: AppSheet Parser Suite - Technical Documentation

As before, I used Claude throughout — for the debugging, for the analysis, and for drafting this post.

2 Likes

I built a Rust-based native app that is basically an appsheet expressions compiler.
With it I discovered the not-so-unknown truth that some of the most “advanced” apps in templates/samples were written by Googlers familiar with GSheets and no real expertise of AppSheet expressions (e.g. heavy use of LOOKUP instead of dereferences).

I have not been able to visualize how to better place it in your hands as a community though, which is why it’s been a private project for the time being.
I have many things I’ve been building for the past 12-18 months but I’m a perfectionist and I don’t want to drop any service that doesn’t provide at least the level of value an expert would provide to users, either newcomers or experts.

I hope I can publish what I have been building regarding agents+appsheet before the end of year. For now, these kind of minor tools may help.

I’d love to know if any of you find something like this useful.

Here is a look of if, the rough v0.1.0


I’ve seen that many use ai agents by letting them analyze the json blob raw or with some scripts, but I tried this like two years ago and it’s not the best way to do it, I think @MultiTech may have some points to share as well.
The json blob must be analyzed deterministically, which is what pushed me to build this Rust parser and compiler for appsheet syntax, which is basically what appsheet has server side in .NET

I hope this doesn’t sound like Rune language

5 Likes

Thanks @SkrOYC ! I think I took on my own scripting project (the project I’ve been sharing in this thread) in part because I wasn’t aware of how complicated it would be. (If I had understood how many hours would be required, I might have thought twice.) And, throughout, I’ve relied heavily on AI for advice and actual coding. I’m still very dependent on AI and so I don’t feel qualified to give advice but I can say that it was AI (Claude) that told me about GitHub and helped me learn how to use it. I wonder if GitHub might not be an appropriate venue for you to share your Rust-based app, if you are willing to do so.

P.S. Rereading your message. I see that I misunderstood; you know how to publish but you’re waiting until you feel ready (the quality is good enough). I probably should have waited longer too. At any rate, I’m looking forward to using what you’ve built when you do share it. :slight_smile:

4 Likes

Hi Kirk!
I understand you pefectly, but it’s also that initial ignorance that allows us to learn and push further. Ignoring the scope of things sometimes is the best way to not limit ourselves and find the ways to accomplish things anyways. You have done a wonderful job at it!

I’m sorry to come up out of the blue with my previous comment btw, I noticed it was confusing.
Sometimes I feel like I’m chatting with friends here and my comments may sound a little out of context.

Anyways, what I shared is one of many small tools I have built. What I want to publish soon is a SaaS, so a different idea overall. This may make things clearer.

Happy to talk to you guys!

5 Likes

Thanks so much!

By the way, I’m working on the scripts right now and learning more about what is and what is not in the HTML “Documentation.” Most of what I need is there but today I learned that the “Display name” information for views is not included while the same kind of information for columns is there. And, of course, bots are not represented at all in the “Documentation.” It seems that AppSheet stopped updating the software that builds the html documentation for individual apps at some point. Still, it has a LOT of useful information.

I’ll keep working. I’m hoping to be able to report progress in the coming weeks. :slight_smile:

3 Likes

AppSheet Parser and Orphan Detector Suite — a substantial update

I’ve just pushed a large batch of fixes to the parser suite, and I want to describe both what changed and where I think this is heading, because the second part has become more interesting to me than the first.

The immediate news: running the scripts against another creator’s app — shared with me generously for testing — the possible-orphan count came down from 105 to 54. Fifty-one of those were the scripts’ own errors, not actual orphans in his app. In other words, they were views that were reachable via routes the scripts couldn’t see.

What caused those errors is the part worth dwelling on. LINKTOFILTEREDVIEW wasn’t in the parser’s list of navigation functions at all. LINKTOFORM actions were excluded by an action-type filter. Map views had no visibility rule written for them. Two whole shapes of CONTEXT() condition — LEFT(CONTEXT(“View”), N) = “prefix” and IN(CONTEXT(“View”), LIST(…)) — were silently dropped, so the edges they restrict arrived looking unconditional. Every one of those was a rule that only ever got written for the cases my own app happened to exercise.

That is the structural problem with this kind of tool, and I don’t think more fixes solve it. A script has to anticipate every shape in advance. The next unanticipated one fails exactly as silently as the last, and you find out when someone else’s app surfaces it — if you’re lucky enough to have someone else’s app.

Which is why the direction I care about is making the app’s data legible to AI rather than making the script’s verdicts sharper. The scripts already output structured CSVs, and there is now a CLAUDE.md and AGENTS.md so an AI assistant reading them knows what each file means and what the suite cannot see. My aim is for a creator to be able to ask questions in plain language — “I made this action and expected it to show up on this view but it isn’t, find out why”, or “I’m looking at this view and can’t remember how a user gets here, tell me the ways” — and get a real answer.

Practical notes. STATUS.md is a public defect list. It records defects in the suite that are still open, defects already fixed and the commit that fixed each, and — separately — things the suite cannot establish at all, because AppSheet’s export doesn’t carry them.

If you run the scripts against your own app, I’d genuinely like to hear about what they missed or got wrong. Every gap fixed this month came from an app that wasn’t mine.

I’m hoping to publish the AI-ready version within a week or so.

Kirk

P.S. Here are some technical notes from Claude:

A concrete example of what the AI-legibility paragraph above is about, from Kirk’s own app this week. One of his actions carries this condition:

or(context(“View”)=“Session”, left(context(“View”),9)=“Session J”)

The parser’s only_if_condition handling scans the raw expression text with a regular expression and collects whatever CONTEXT() clauses it finds. It has no model of the boolean structure around them, so it captured the first alternative, dropped the second, and concluded the action was unavailable on a view where it plainly is available — confirmed by opening the app and looking.

The same flat scanning cuts the other way too. In a second case it accumulates two clauses that the expression’s own structure keeps apart, producing two navigation edges the app does not have. That is now recorded as a defect with both wrong rows named, rather than left as an approximation.

And a third shape defeats the pattern entirely. This one is not a view restriction at all:

IF(left(CONTEXT(“View”),20) = “Session confirmation”, NUMBER([Text2]) = [Number], TRUE)

The LEFT test selects which data condition applies; the else-branch is TRUE, so the action is available everywhere. A parser that hoisted every LEFT it found into a view restriction would wrongly refuse most of that action’s edges. Avoiding it required a special-case guard.

Fixing this properly means parsing boolean structure — building an expression tree, knowing that an OR unions and an AND intersects and an IF does neither. That is a real interpreter where there is currently a regex, and it would need re-verifying every condition the suite produces. For a volunteer project, that is a large cost for cases whose shapes cannot be enumerated in advance anyway.

The alternative Kirk is exploring: the raw expression is already preserved on every edge in the output, so a reader that understands AppSheet expressions can settle these directly. All three cases above are ones a language model reading the expression gets right, including the IF-with-TRUE-else-branch that defeated the regex.

One condition makes or breaks that approach, and it is not met yet. A condition mangled by an unparsed OR is byte-identical in the output to a cleanly parsed one — same six columns, same format. So a reader has no way to know which conditions to re-read and which to trust. The tool has to be explicit about what it could not interpret, or “check this one” is not available as an answer. That is the next design problem rather than a solved one, and it is why the defect list is public.

2 Likes

One of my “small tooling apps” is an browser extension (both firefox and chromium) to visualize the schema (data-model) in a 3d graph, similar to this: https://vasturiano.github.io/3d-force-graph/example/text-nodes/

If enough people is interested I may drop it in the stores (for free of course)

3 Likes

Not to diminish your work, but this is already built into the app editor:

Sure!
I find it very basic though. Plus it ignores Enum/Enumlist with basetype Ref.
I needed one that was more than a gimmick haha

2 Likes