← The ADLC library
Field guides · 42

Deriving status from source control instead of maintaining it in Asana

A practical route to keeping Asana in step with what engineering is actually doing, starting with the identifier problem that makes Asana harder to automate than a developer tracker.

Asana holds the plan. The engineers work in GitHub, GitLab or Bitbucket. Nobody updates Asana, so the project owner does it on their behalf by asking people, and the board becomes a record of the last time somebody was asked rather than the state of the work.

This is a solvable problem, but Asana is genuinely harder to automate than a developer tracker, and the reason is specific enough to be worth understanding before you start.

The identifier problem, which is the whole thing

A developer tracker gives every item a short human key. Somebody types it into a branch name without thinking, and every downstream system can resolve it from a string.

Asana does not work that way. A task is identified by a long numeric ID that appears in its permalink. Nobody memorises it, nobody types it into a branch name, and the moment you ask them to, the convention dies. So the first job is not automation. It is deciding how a commit is going to point at a task at all.

There are three workable answers.

Paste the task URL into the pull request description. Lowest friction by a distance. People already copy task links into Slack. The numeric ID is right there in the URL and is trivial to parse. The cost is that it lives in the pull request rather than the branch, so you learn about the link later in the cycle.

Carry a short key in a custom field. Maintain a human-friendly identifier on the task yourself, generated or manually assigned, and require it in branch names. This gives you the developer-tracker experience, at the cost of maintaining an identifier scheme Asana does not know about. It works best when the number of tasks that reach engineering is modest.

Use the numeric ID directly in the branch name. Ugly, and perfectly reliable, particularly if branch names are generated by a script or a snippet rather than typed.

Pick one and only one. Two conventions in parallel means every consumer has to handle both, forever.

Why the usual approach fails

  • No short key exists to type
  • Completion is a single checkbox
  • Stage lives in a section or a field, by convention
  • Integrations mostly attach links, not lifecycle

What to establish first

  • One agreed way a change points at a task
  • A custom field that holds engineering stage
  • Completion reserved for genuinely finished
  • A measured linking rate, published weekly
Every automation you build later depends on the two decisions on the right. Getting them wrong is expensive to unwind because the convention is already in people's hands.

Strong in one direction, weak in the other

More than people expect, in one direction, and less than people expect in the other.

Rules. Asana’s automation can fire on task changes and then move a task between sections, set a custom field, assign, add collaborators or complete it. This is a real workflow engine and it is capable of expressing most of what a delivery board needs. Availability and the number of rules you get vary by plan, so check yours before designing around it.

Custom fields. This is where engineering stage belongs. Asana’s native completion is a boolean: a task is complete or it is not. There is no room in that for “in review” or “merged, awaiting release”. A single-select custom field gives you the states you actually need and, unlike sections, it travels with the task across projects.

Sections. Useful for the visual board, but scoped to a project. A task in three projects has three positions, which makes sections a poor place to keep the canonical answer.

The API and webhooks. Asana has a full API, which is what you will write to. It also emits webhooks, but note the direction: those tell you about changes made in Asana. Deriving status is the opposite flow, so you will be consuming source control events and calling the Asana API, not consuming Asana’s webhooks.

Source control integrations. Asana connects to the major hosts. What each connector actually writes back varies significantly by integration and version, and most of them are oriented around attaching a pull request to a task rather than driving the task’s lifecycle. Install yours and test what it does with a real pull request before you build a plan on top of it. Do not assume it completes tasks on merge unless you have watched it happen.

The connector attaches. It does not derive.

The connector attaches, it does not derive. Seeing a pull request on a task is useful. It still leaves a person to interpret it and move the task, which is the labour you were trying to remove.

The boolean. Because completion is binary, “done” in Asana means whatever your team has agreed it means, and that agreement is not written down anywhere the tool can enforce. Two people will use it differently within a month.

Rules act on Asana events, not repository events. Asana automation is excellent at reacting to something changing in Asana. It has no native concept of a branch appearing or a deployment landing. Something outside Asana has to translate.

Cross-project tasks. The same task in a delivery project and a leadership portfolio can appear to be in two different stages if stage is modelled by section. This is the single most common cause of a leadership board disagreeing with the delivery board.

Non-engineering work is the majority. Asana is usually the whole company’s tool, not engineering’s. Anything you build that derives status from source control covers a slice of the workspace and must not make the rest look stalled by comparison.

Establish the convention, then measure it

Establish the link convention and measure it. Same discipline as any tracker: publish, weekly, the merged pull requests with no resolvable task. Argue about the list, not the percentage.

Add a stage custom field and stop overloading completion. Backlog, in progress, in review, merged, released. Reserve the completion checkbox for released. This costs an afternoon and removes most of the ambiguity in the standup.

Have deployments recorded somewhere. Whatever your CI, make it produce a deployment record naming an environment. Without it, your derivation cannot distinguish merged from live, and the distinction is the one your stakeholders care about.

Then write the small service. Source control webhook in, identifier resolved, Asana API call out to set the stage field. Make it idempotent, re-fetch the pull request rather than trusting the payload, and log every event you could not resolve to a task. That unresolved log is your linking-rate report and it will be more useful than the service for the first month.

If you would rather buy this, it is worth knowing what you would be buying before you spend time on a demo. We build GroundTruth to derive delivery status from GitHub, GitLab and Bitbucket. For Asana specifically we support read plus coarse write, not the full two-way sync we run for Jira, Linear and Azure DevOps. If you need fine-grained state written back into Asana, that is a real gap on our side and you should establish it early rather than late.

Where this breaks down

Asana may not be where the work belongs. If engineering work has grown into a lifecycle Asana was not built to model, the honest answer is sometimes a developer tracker for engineering with Asana holding the programme view, and the integration between them rather than the automation inside them.

Automation makes the plan look healthier than it is. A board that updates itself reads as authoritative. If your linking rate is sixty percent, forty percent of the work is invisible and the board will not tell you which forty.

Custom fields proliferate. The stage field you add is the fifth single-select on the task, and by next quarter someone has added a sixth that overlaps with it. The tool will not stop you. Decide who owns the field schema on day one.

The manual update was sometimes doing work. Marking a task complete is a person taking responsibility for a claim. If your definition of done includes anything a repository cannot observe, keep that final act human and derive everything up to it.