Tricks to make Antigravity IDE do EXACTLY what you want when programming

- Andrés Cruz - ES En español

Video thumbnail

I want to share a couple of tricks and considerations so that Google Antigravity (or any coding AI) generates exactly what you are looking for when you need to implement specific functionalities. These tips serve me daily, and I am sure they will help you too.

1. Context: The difference between authenticated users and visitors

Imagine I want to add a new functionality to my academy application. In it, you can see paid courses (where the user must be authenticated) and free material (where it is not necessary).

This is a critical point:

  • With authentication: I can save progress in the database using the user's ID.
  • Without authentication: I don't know who the user is, so the logic changes completely.

Knowing this situation, I evaluate my code. Currently, I handle the payment and authentication logic, but I have left a space (an else) specifically for free content. This is where I want to manage progress locally.

️ How to write the suggested "Prompt"

To prevent the AI from inventing solutions I don't want, I follow this outline:

  • Provide context: I explain the problem and the current situation.
  • Give clear guidelines: I indicate the technical solution I prefer. In this case, I ask it to use LocalStorage as persistent browser storage.

The browser has several types of storage (Cookies, IndexedDB, etc.), but I prefer LocalStorage for its simplicity. You can see what is stored by inspecting your browser in the Application > Local Storage tab.

The Relative URL and Exact Location trick

To prevent the AI from getting lost in a sea of files (as happens in large Laravel projects), I use two vital tricks:

  1. Copy the relative path: Right-click on your file and select "Copy Relative Path". Paste it into the chat so the AI knows exactly where to work.
  2. Point out the code block: I give it the exact piece of code where I want the implementation. For example, I tell it to look for the watch that monitors the classIndex and sectionIndex properties to update the progress locally if the resource is free.

Modularization and Best Practices (Pinia and Vue)

To prevent the AI from "spitting out" all the code into a single file, I give it modularization instructions. In my case, I use Pinia to handle the state.

The AI generated a local function to save progress given the courseID, the section, and the class, but delegated the storage logic to a separate file managed by Pinia. This keeps the code clean and professional. If your request is too general, the AI will tend to do everything locally, which is difficult to maintain.

Comparison: Challenges in Flutter and Global Configurations

When you request global changes (like setting up payments in a Flutter app), precision is even more important. If the prompt is too vague, errors can occur:

  • Obsolete versions: AI usually installs old plugins. I indicate the exact version or explicitly ask for the latest version.
    • I told it exactly which version I wanted it to install.
  • Forgotten files: In a Flutter project, the AI modified the pubspec.yaml but forgot the AndroidManifest.xml. Without the permissions in the latter, the functionality simply doesn't work.
    • The prompt was to add the in_app_purchase package to make purchases through Google Play in a Flutter project, which requires adding the <uses-permission android:name="com.android.vending.BILLING" /> permission—an operation it did NOT do until I asked a second time.

If you don't dictate exactly which files to touch, the harmony of the project is lost and the code becomes unmanageable. Since, when starting multiple conversations, the AI often does NOT evaluate the ENTIRE project and might skip some existing implementations, adding redundancy and changing the programming style. That is why it is important to make specific changes indicating exactly what you want it to do and for YOU to verify those changes.

The Ideal Workflow: Test and Sync

What I like most about tools like Antigravity is that they mark exactly which lines changed in yellow (if you use Git). My workflow is as follows:

  1. Analyze: I review the yellow change markers.
  2. Execute and Test: I verify that it is functionally OK.
  3. Sync: If the change is correct, I run git add, git commit, and git push.
  4. Revert if necessary: If something goes wrong, I use the git reset --hard command to return to the previous state and try again.

Summary: Give it context, give it the relative URL of the file, review specific changes, and constantly sync with Git.

Google Antigravity: How to use AI to speed up your programming (e.g., Django app)

Video thumbnail

It's time for another practice to expand our capabilities through Artificial Intelligence. This time, we will use Google Antigravity, a modified version of VS Code designed to boost workflow with intelligent agents.

If you want to follow this practice, you can download the tool directly from its official page. The fundamental difference with the traditional editor is that it includes an Agent tab and a Planning tool, which is what we will explore today.

I believe that the current way of programming involves using an AI. If you don't use it, your competition will, and you will lose ground. In this course, we balance traditional teaching with these tools to streamline developments we've already covered previously, such as creating listings and details.

The Project: Blog Module with Django

For this practice, I asked the AI to develop a Blog module that we were missing. The goal was to create:

  1. Post listing: With filters by categories, types, and pagination.
  2. Detail page: Layouted with Bootstrap.
  3. Existing models: Instead of creating a new model from scratch, I instructed it to use our "elementos" model (which simulates posts) and its relations with category and type.

This is the prompt:

Create a module in the elements app to have a Blog with filters by types, category, pagination, and layouted with Bootstrap, containing both the listing and the detail view.

It's a prompt that could be much improved since we did NOT specify aspects like whether we want it to create a model (in our case, we want it to use the Elements relationship):

class Category(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255,blank=True)
    
    def __str__(self):
        return self.title
    
class Type(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255,blank=True)
    
    def __str__(self):
        return self.title
class ElementManager(models.Manager):
    def get_queryset(self):
        # Siempre que usemos Element.objects.all(), incluirá el select_related
        return super().get_queryset().select_related('category', 'type')
    
class Element(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255,blank=True)
    description = models.TextField() # blank=True, null=True
    price = models.DecimalField(max_digits=10,decimal_places=2, default=6.10) # 12345678.10
    category = models.ForeignKey(Category, on_delete=models.CASCADE) #, related_name='elements'
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    type = models.ForeignKey(Type, on_delete=models.CASCADE)

We didn't provide screenshots of how we want the development to look, among other aspects you might want to add. However, by indicating which app it needs to inspect (the elements app), we save some tokens and time when Google Antigravity begins to evaluate the project.

Even so, with this, we can interact with the tool and learn how it works.

The Planning Tool

This is the main advantage of Antigravity compared to other tools like Gemini CLI or Agent. Before executing any code, the agent generates a Roadmap.

The AI tells you exactly which files it is going to modify or create:

Add changes to the detail route

Figure 18-4: Roadmap generated by Google Antigravity

As you can see in the Roadmap, the AI wants to generate a new model, which is not what we want (and this is because we gave it a poor prompt), but we have the opportunity to correct it and tell it to "Not create a new model, use the Element one instead."

If the AI tries to create a model named Post and you want it to use Elements, you can add a comment in the planning. It will readjust its plan before touching a single line of code.

As a security recommendation, always sync your project with Git before accepting changes. If the result is not as expected, you can easily go back with a git reset --hard HEAD.

Additionally, the editor once got stuck "Thinking..." indefinitely, because it encountered an error while trying to start the virtual environment and run the command to generate the migrations:

python manage.py makemigrations
zsh: command not found: python

    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?

I executed the command manually and told the AI ​​Agent to run the command for it, but the Agent still did not respond, so I had to finish its execution and restart it to tell it to continue with the execution of generating the views and templates (which was the next task to perform).

Implementation and Results

After a few iterations in which you must do the same as before, view the Roadmap and if one of the developments suggested by the AI doesn't match what you want to do, add a comment and click the "Proceed" button in the upper right corner until you have a clear Roadmap for your application.

In the end, the AI generated a functional layout based on Bootstrap cards with filters for categories and listings, and a detail page:

Resulting blog

Features of the generated development

Dynamic Filters: The view optionally checks if a category or type parameter exists in the URL and adjusts the initial query:

elements\views.py

def blog_list(request):
    elements = Element.objects.select_related('category', 'type').all()
    
    # Filters
    type_slug = request.GET.get('type')
    category_slug = request.GET.get('category')
    if type_slug:
        elements = elements.filter(type__slug=type_slug)
    
    if category_slug:
        elements = elements.filter(category__slug=category_slug)

Query Optimization: It used select_related to fetch category and type relationships, avoiding the N+1 query problem (a common error that slows down applications):

elements = Element.objects.select_related('category', 'type').all()

elements\views.py

Slug Handling: It configured the routes to use the slug field instead of the ID (PK), which is much better for SEO:

elements\urls.py

path('blog/<slug:slug>/', blog_detail, name='blog_detail'),

elements\views.py

def blog_detail(request, slug):
    element = get_object_or_404(Element, slug=slug)
    return render(request, 'elements/blog_detail.html', {'element': element})

Pagination: It implemented the logic to read the page parameter and pass the corresponding objects to the template.

Conclusions

As we can see, these types of tools give us many advantages in modern development, although you might not get the exact same result if you perform a similar interaction. For example, I did this test twice on the same base project and in the first interaction I had to make additional corrections, such as indicating to use the slug instead of the PK table. Additionally, I completed the development by telling it in a second prompt to apply a similar design and use a similar typography based on reference images for the listing and details:

elements\templates\base.html

<!-- Google Fonts -->
    <link
        href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,700;1,400;1,700&family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap"
        rel="stylesheet">
    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
    <style>
        body {
            font-family: 'Lora', 'Times New Roman', serif;
            font-size: 20px;
            color: #212529;
        }
        h1,
        h2,
        h3,
        h4,
        h5,
        h6 {
            font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
            font-weight: 800;
        }
    </style> 

In summary, although the AI can infer design from attached screenshots, manual adjustments are always necessary. For instance, in this practice, we had to fix minor syntax errors in the templates (like improperly closed tags). Remember that these are just tools and they do NOT replace a programmer.

A practical guide to Google Antigravity: How to pass effective and accurate prompts based on EXACTLY what you want the Agent to generate.


Únete a la comunidad de desarrolladores que han decidido dejar de picar código y empezar a construir productos reales. Recibe mis mejores trucos de arquitectura cada semana:

I agree to receive announcements of interest about this Blog.