Мы живём в новом смелом мире, и прототипирование стало намного интереснее

Главная страница Фернау

Я был поражён тем, насколько быстро отдельные разработчики теперь могут выпускать реальные и полезные прототипы.

Такие инструменты, как Claude Code, Google AntiGravity и растущая экосистема вокруг них, пересекли определённый порог: вы можете посмотреть, что строят другие онлайн, и понять, насколько быстро вы можете разрабатывать сегодня.

В последние недели я стал уделять один-два часа в день исключительно разработке с моим AI-первым стеком:

  • Google AntiGravity
  • Google Gemini Pro
  • Модели Claude, доступные через AntiGravity

Эта конфигурация фундаментально изменила мой подход к прототипированию, скорости итеративного развития и тому, что персональный AI-агент реально может делать сегодня. Что ещё важнее, это вернуло меня к практическому кодированию и разработке — чем я пожертвовал, когда моя роль в DareData сместилась от выполнения к управлению и координации.

Для отдельного разработчика эта революция — благословение. Она устраняет компромисс, который я принял: что развитие компании означает полный отказ от разработки. Больше я не должен выбирать между разработкой и управлением — они фактически усиливают друг друга.

Но есть и более широкие последствия для простых разработчиков. Если AI-агенты всё чаще берут на себя выполнение, то чистая имплементация перестаёт быть достаточной. Разработчиков будут подталкивать (хотят они того или нет) к координации, принятию решений и... управлению — что ненавидят индивидуальные разработчики. Другими словами, управленческие навыки становятся частью технического стека, а AI-агенты — частью контекста, которым управляют.

Меня больше всего удивило, насколько переносимы мои существующие управленческие навыки:

  • Направление агента вместо микроменеджмента
  • Запрос результатов вместо инструкций
  • Определение приоритетов и указание на неясные области

На практике я управляю и координирую виртуального сотрудника. Я могу глубоко влиять на некоторые части его работы, оставаясь почти полностью невежественным в других — и это не баг, это огромное преимущество. В моём персональном AI-ассистенте, например, я хорошо разбираюсь в бэкенде, но практически ничего не понимаю во фронтенде. Система всё равно работает, потому что моя роль больше не в том, чтобы знать всё, а в том, чтобы направлять систему в правильном направлении.

Это прямая аналогия с тем, как я координирую людей в компании. По мере роста DareData мы не нанимаем копии основателей. Мы намеренно нанимаем людей, которые могут делать то, чего не можем делать мы, и со временем — то, что мы никогда не научимся делать достаточно хорошо.

Текущий стек разработки

Достаточно саморефлексии по поводу управления. Давайте посмотрим, что я разрабатываю, потому что для этого вы здесь:

  • Персональный AI-ассистент, разработанный вокруг моих реальных рутин, а не универсального шаблона производительности. Он адаптируется к тому, как я работаю, думаю и принимаю решения.
  • Мобильное приложение, которое рекомендует один музыкальный альбом в неделю без традиционной системы рекомендаций. Без усиления зоны комфорта, что помогает мне расширять музыкальные горизонты.
  • Мобильная игра с одним персонажем, прогрессирующим через многоуровневые подземелья, разработанная в первую очередь как творческая площадка, а не коммерческий продукт.

Интересно то, что я относительно комфортно работаю с большей частью бэкенда, но фронтенд-разработка — это не мой навык. И если бы я был вынужден делать это самостоятельно, эти проекты замедлились бы с часов до дней, или просто никогда не были бы выпущены.

Это ограничение теперь почти полностью исчезло. С новым стеком воображение становится реальным узким местом. Стоимость "незнания" целого слоя упала.

Итак, в остальной части этого поста я пройдусь по моему персональному AI-ассистенту: что он делает, как он структурирован и почему это работает для меня. Моя цель — открыть исходный код, когда он стабилизируется, чтобы другие могли адаптировать его к своим рабочим процессам. Сейчас это очень специфично для моей жизни, но эта специфичность намеренна, и сделать это более универсальным — часть эксперимента.

Встречайте Фернау

Фернау Лопеш был летописцем португальской монархии. Я выбрал португальскую историческую фигуру намеренно — португальцы имеют привычку присваивать исторические имена почти всему. Если это звучит типично португальски, то это намеренно.

Фернау Лопеш, летописец Португальского королевства

Фернау — португалец, но на самом деле говорит по-английски. Назовём его современным летописцем XXI века.

На данный момент я делаю две вещи, которых обычно избегаю: наделяю AI человеческими чертами и поддаюсь очень португальскому инстинкту называния. Считайте это безобидным знаком того, что я становлюсь старше.

Кроме того, что Фернау на самом деле для меня делает? Лучше всего начать с его главной страницы.

Главная страница Фернау

Фернау — крутой парень, который сейчас выполняет пять задач:

  • Расписание дня: планирует мой день, собирая календари, списки дел и задачи, затем превращая их в нечто, что я могу выполнять.
  • Помощник по писательству: помогает мне проверять и чистить черновики блог-постов и других текстов.
  • Помощник портфеля: предлагает компании или ETF для добавления на основе потребностей переbalансировки и глобальной ситуации (без претензий на ясновидение).
  • Финансовый организатор: извлекает расходы из выписок по банковским счётам и загружает всё в приложение Cashew, избавляя меня от ещё одной задачи, которая занимала около 3-4 часов в месяц.
  • Подписки и скидки: отслеживает все мои подписки и выводит скидки или преимущества, которые у меня, вероятно, есть, но я никогда не помню использовать.

В этом посте я сосредоточусь на приложении Day Schedule.

На данный момент расписание дня Фернау выполняет три простые вещи:

  • Получает мой календарь, включая все запланированные встречи
  • Извлекает мои дела из Microsoft To Do
  • Получает мои личные ключевые результаты из Notion

Всё это подключено через API. Идея проста: каждый день Фернау смотрит на мои ограничения, приоритеты и обязательства, затем генерирует для меня лучшее возможное расписание.

Текущие возможности Фернау

Сгенерировать расписание на фронтенде довольно просто (весь фронтенд был написан по вибрации). Вот кнопка генерирования расписания:

Генерировать расписание на конкретный день

Когда я нажимаю "Generate Schedule", Фернау начинает работать в фоне:

Фернау генерирует расписание

Шаги затем выполняются по порядку: получение моего календаря, задач и данных из Notion.

Следующий момент также является местом, где базовая грамотность в кодировании действительно начинает иметь значение, не потому, что всё, что делает следующий код, не работает, а потому, что вам нужно понимать что происходит и где вещи могут в итоге сломаться или потребовать улучшений.

Начнём с получения календаря. На данный момент это обрабатывается одной гигантской функцией, созданной Claude, которая полностью неоптимизирована.

def get_events_for_date(target_date=None):
    """
    Fetches events for a specific date from Google Calendar via ICS feeds.
    
    Args:
        target_date: datetime.date object for the target day. If None, uses today.
    
    Returns a list of event dictionaries.
    """
    # Hardcoded calendar URLs (not using env var to avoid placeholder issues)
    CALENDAR_URLS = [
        'cal1url',
        'call2url'
    ]
    
    LOCAL_TZ = os.getenv('TIMEZONE', 'Europe/Lisbon')
    
    # Get timezone
    local = tz.gettz(LOCAL_TZ)
    
    # If no target date provided, use today
    if target_date is None:
        target_date = datetime.now(local).date()
    
    # Create datetime for the target day boundaries
    day_start = datetime.combine(target_date, datetime.min.time()).replace(tzinfo=local)
    day_end = day_start + timedelta(days=1)
    
    # Debug: Print the date range we're checking
    print(f"\n[Debug] Checking calendars for date: {target_date.strftime('%Y-%m-%d')}")
    print(f"  Start: {day_start.strftime('%Y-%m-%d %H:%M %Z')}")
    print(f"  End: {day_end.strftime('%Y-%m-%d %H:%M %Z')}")
    print(f"  Timezone: {LOCAL_TZ}")
    
    all_events = []
    
    # Fetch from each calendar
    for idx, cal_url in enumerate(CALENDAR_URLS, 1):
        calendar_name = f"Calendar {idx}"
        print(f"\n[Debug] Fe