Every internal tool I’ve built for this firm has had the same first bug, and it was never in the code.
The tool asks a question the user can’t answer.
The user isn’t the problem. The people using these systems are lawyers and legal assistants who juggle hundreds of deadlines without dropping one. The question is written in a language they’ve got no reason to speak: the language of the toolkit the thing was bolted together from.
Here’s the classic version. A tool that starts a working session puts up a field labeled:
Working directory
And underneath it, helpfully, a placeholder showing a path.
I’ve watched a smart person type the word downloads into that field, because they had a document in their Downloads folder and that seemed like the answer. Read the question the way a normal person would, and it’s a perfectly reasonable answer. To the software, it meant nothing. The program went looking for a folder named downloads relative to wherever the server happened to be running, found nothing, and threw an error about a directory.
Your first instinct is to write a better error message. Don’t. The answer wasn’t the problem. The question was.
(Everything in this article uses invented examples. No client information, matter numbers, or real file paths appear anywhere in it.)
Nobody outside software knows what a “working directory” is
Make a list of the words that leak out of developer tools and into screens built by people who aren’t developers:
- working directory
- root
- path
- instance
- environment
- config
- token
- endpoint
Every one of them is precise and standard, and not one means a thing to somebody whose expertise is Minnesota civil procedure. They aren’t hard words. They’re another profession’s words, dropped into a tool this one has to use.
Here’s how they get in. When you build a tool, you build it in the vocabulary of whatever you built it with. The library you called wanted a working directory, so your form asks for a working directory. You’ve basically handed your dependency’s API straight to a human being.
Any lawyer would spot this in a different setting. It’s the same mistake as sending a client a letter that says “we will be seeking Rule 37 sanctions for your ex-husband’s failure to respond to our Rule 34 requests.” Every word is right. The client has no idea what you’re about to do.
Don’t fix the label. Change the question.
Here’s what fixed it for us.
The tool never actually needed to ask where on the filesystem should this run. That was a piece of plumbing that got promoted to a question for the user. What the tool needed to know was:
What are you working on?
And everybody in a law office can answer that in a heartbeat, because it’s how the whole practice is organized. A matter.
So the field changed. Instead of a text box waiting for a path, the tool gives you a chooser whose first tab, the default, lists every matter folder on disk, searchable by file number or client name. Type three digits of a file number, or the first four letters of a client’s last name, and there it is. The tool works out the path. The path was never the user’s problem.
That’s the whole idea, and it travels:
Ask for the domain object the user already thinks in. Derive the machine detail yourself.
Your people think in matters, clients, deadlines, hearings, and documents. They don’t think in paths, IDs, or endpoints. Anywhere your screen asks for the second kind of thing, there’s a translation you never wrote.
Then make typing work anyway
A picker won’t cover every case, and some people would rather type. So the text field stayed. It just quit acting like a validator and started acting like an interpreter.
The rule I landed on: accept anything that clearly names a real folder, and tell the user what you decided it meant.
So now the field takes all of these:
| What gets typed | What it resolves to |
|---|---|
downloads |
the Downloads folder in the user’s home |
~/Desktop |
the Desktop folder |
| a bare matter number | that matter’s folder |
| a folder dragged in from Finder | the folder that was dragged |
| a path with quotes or escaped spaces | the path, cleaned up |
None of that is clever. Matching that ignores capital letters, expanding the tilde, stripping the junk copy-and-paste adds, and one lookup against the matter index. An hour of work, total.
What matters more than any of it is that last part. Under the field, before anything runs, the tool shows what it resolved to — the readable path, plus the matter number if it recognized one. If the user typed something wrong, they see it right away, in a form they can actually check, while it’s still free to fix.
Put the two side by side:
- Validator: you type something, you hit go, you get an error about a directory. You try again. You give up and go ask somebody.
- Interpreter: you type
downloads, and the tool says✓ ~/Downloadsbefore you commit. Either you nod or you notice it’s wrong.
Same input. Nearly the same code. A completely different tool to use.
Three Mac tricks worth teaching anyway
The interpreter handles most of it. But a little user know-how pays off everywhere — in this tool and in every open/save dialog anybody in the office will ever see.
1. Select a folder in Finder and press ⌘⌥C. That copies its full path to the clipboard, ready to paste. Most Mac users have never been told it exists.
2. Drag the folder onto the field. Finder hands over a file:// URL, and a well-built field will turn that into a path. It’s the easiest one to find and there’s nothing to learn.
3. In any Mac open/save dialog, press ⌘⇧G. That opens a “Go to Folder” box with autocomplete.
Fifteen minutes teaching those three shortcuts gets rid of more friction than most interface work.
What a web page can’t do
If you’re building firm tools as browser apps, and in 2026 that’s the sensible default, know this going in.
A web page can’t open a folder chooser. There’s no way around it. An <input type="file"> hands JavaScript a file, never a path, and the directory variants don’t change that. If your internal tool runs in a browser tab, your people will be typing or pasting paths forever, and the interpreter above isn’t a nice extra. It’s the whole interface.
Wrap the same app in a thin native shell — a few hundred lines, and you get a Dock icon out of the deal — and you can reach from the page to a real system folder panel. Then people get the file chooser they’ve used since they were kids. That’s a real reason to build the native wrapper, and it’s got nothing to do with how the app looks.
Either way, build the matter picker. Even with a perfect native chooser, searching 600 matter folders by file number beats clicking down four levels of a Dropbox tree every single time.
Why it’s worth an afternoon
It’s tempting to call this polish. The automation is the real work, and the input field is trim.
I think that’s exactly backwards, and the reason is specific to small firms.
An internal tool with a hostile screen doesn’t get used badly. It gets used by one person: whoever built it, the only one who knows what the fields mean. Everybody else quietly works around it and goes back to doing the job by hand. Then you decide the workflow wasn’t worth automating, when what really happened is you put a vocabulary test at the front door.
That test is the cheapest thing in the whole system to get rid of. You don’t need better models, more integration, or a rewrite. You need to notice you asked for a path when you meant a matter. Then ask for the matter.
Sources
- Apple, macOS Finder keyboard shortcuts (⌘⌥C to copy a file or folder path; ⌘⇧G to open “Go to Folder”), verified in macOS.
- HTML Standard, file upload state (
<input type="file">), which exposes selected files to script asFileobjects and does not expose filesystem paths — verified against the specification’s file upload state andFileListbehavior.
This article describes general design practice for internal law firm tooling. All examples are invented. It contains no client information and is not legal advice.